package com.camilstaps.common;
import android.content.Context;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Date
*
* @author Camil Staps
*/
public class Date implements Comparable<Date> {
private int year, month, day;
/**
* Constructor without parameters creates a Date for the current date
*/
public Date() {
Calendar cal = Calendar.getInstance();
year = cal.get(Calendar.YEAR);
month = cal.get(Calendar.MONTH) + 1;
day = cal.get(Calendar.DAY_OF_MONTH);
}
/**
* Constructor to specify year, month and day
* @param year
* @param month
* @param day
*/
public Date(int year, int month, int day) {
this.year = year;
this.month = month;
this.day = day;
}
/**
* Constructor to parse a Date from a String
* @param format the String in YYYY-mm-dd format
* @throws ParseException if the format was incorrect
*/
public Date(String format) throws ParseException {
Pattern pat = Pattern.compile("(\\d*)-(\\d*)-(\\d*)");
Matcher match = pat.matcher(format);
if (match.find()) {
year = Integer.parseInt(match.group(1));
month = Integer.parseInt(match.group(2));
day = Integer.parseInt(match.group(3));
} else {
throw new ParseException("Wrong date format", 0);
}
}
/**
* Copy-constructor
* @param copy
*/
public Date(Date copy) {
year = copy.year;
month = copy.month;
day = copy.day;
}
public int getYear() {
return year;
}
public int getMonth() {
return month;
}
public int getDay() {
return day;
}
/**
* Add some amount of years
* @param n
*/
public void addYears(int n) {
year += n;
}
/**
* Subtract some amount of years
* @param n
*/
public void subtractYears(int n) {
year -= n;
}
/**
* Add some amount of months
* @param n
* @todo This could be optimized by removing the for loop
*/
public void addMonths(int n) {
for (int i = 0; i < n; i++) {
month++;
if (month >= 13) {
month = 1;
addYears(1);
}
}
}
/**
* Subtract some amount of months
* @param n
* @todo This could be optimized by removing the for loop
*/
public void subtractMonths(int n) {
for (int i = 0; i < n; i++) {
month--;
if (month <= 0) {
month = 12;
subtractYears(1);
}
}
}
/**
* Add some amount of days
* @param n
* @todo This could be optimized by removing the for loop
*/
public void addDays(int n) {
for (int i = 0; i < n; i++) {
day++;
if (day >= daysOfMonth()) {
day = 1;
addMonths(1);
}
}
}
/**
* Subtract some amount of days
* @param n
* @todo This could be optimized by removing the for loop
*/
public void subtractDays(int n) {
for (int i = 0; i < n; i++) {
day--;
if (day <= 0) {
month--;
day = daysOfMonth();
}
}
}
/**
* Add (if n>0) or subtract (if n<0) some amount of days
* @param n
*/
public void addOrSubtractDays(int n) {
if (n < 0) {
subtractDays(-n);
} else {
addDays(n);
}
}
/**
* Check if a year is a leap year
* @param year
* @return
*/
public static boolean isLeapYear(int year) {
if (year % 4 != 0)
return false;
if (year % 100 != 0)
return true;
if (year % 400 != 0)
return false;
return true;
}
/**
* Check if this date is in a leap year
* @return
*/
public boolean isLeapYear() {
return isLeapYear(year);
}
/**
* Give the number of days in a year
* @param year
* @return
*/
public static int daysOfYear(int year) {
return isLeapYear(year) ? 366 : 365;
}
/**
* Give the number of days in this year
* @return
*/
public int daysOfYear() {
return daysOfYear(year);
}
/**
* Give the number of days in a month
* @param year
* @param month
* @return
*/
public static int daysOfMonth(int year, int month) {
switch (month) {
case 2: return isLeapYear(year) ? 29 : 28;
case 1:
case 3:
case 5:
case 8:
case 10:
case 12:
return 31;
default:
return 30;
}
}
/**
* Give the number of days in this month
* @return
*/
public int daysOfMonth() {
return daysOfMonth(year, month);
}
/**
* Give the (absolute value of the) difference in days with another Date
* @param withDate
* @return
*/
public int diffDays(Date withDate) {
Date smaller, bigger;
if (compareTo(withDate) > 0) {
smaller = new Date(this);
bigger = new Date(withDate);
} else {
smaller = new Date(withDate);
bigger = new Date(this);
}
if (smaller.equals(bigger)) {
return 0;
}
int i = 0;
while (!smaller.equals(bigger)) {
smaller.addDays(1);
i++;
}
return i;
}
@Override
public int compareTo(Date another) {
if (another.year != year)
return compareIntegers(another.year, year);
if (another.month != month)
return compareIntegers(another.month, month);
if (another.day != day)
return compareIntegers(another.day, day);
return 0;
}
/**
* Integer.compare was added in API level 19, so this is for compatibility
* @param x
* @param y
* @return
*/
private int compareIntegers(int x, int y) {
if (x == y) return 0;
return (x < y) ? -1 : 1;
}
/**
* Check if two objects represent the same date
* @param date
* @return
*/
public boolean equals(Date date) {
return year == date.year && month == date.month && day == date.day;
}
/**
* Present the date in a 'nice' String, according to the user's localization
* @param context
* @return
*/
public String toNiceString(Context context) {
SimpleDateFormat sdf = new SimpleDateFormat("EEEE d MMMM y");
return sdf.format(new GregorianCalendar(year, month - 1, day).getTime());
}
@Override
public String toString() {
return Integer.toString(year) + "-" + Integer.toString(month) + "-" + Integer.toString(day);
}
}