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 { 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); } }