/* * Copyright (C) 2012-2016 The Android Money Manager Ex Project Team * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 3 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package com.money.manager.ex.utils; import android.support.annotation.NonNull; import android.text.TextUtils; import com.money.manager.ex.Constants; import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; import java.util.GregorianCalendar; import java.util.Locale; import java.util.TimeZone; import timber.log.Timber; /** * Expanded Date type, matching JodaTime and other APIs. */ public class MmxDate { /** * The expected format is full ISO format: 2016-10-22T02:36:46.000+0200 * @param dateString The date string in ISO format. * @return MmxDate instance. */ public static MmxDate fromIso8601(String dateString) { if (dateString.length() < 28) { // manually handle short time-zone offset, i.e. 2016-10-22T02:36:46.000+02 if (dateString.charAt(23) == '+' || dateString.charAt(23) == '-') { // append two zeroes dateString = dateString.concat("00"); } // handle invalid format 2016-10-21T18:42:18.000Z if (dateString.charAt(23) == 'Z') { dateString = dateString.substring(0, 23); // append the current time zone time DateFormat offsetFormat = new SimpleDateFormat("Z"); String offsetString = offsetFormat.format(new MmxDate().toDate()); dateString += offsetString; } } return new MmxDate(dateString, Constants.ISO_8601_FORMAT); } public static Date from(String dateString, String pattern) { if (TextUtils.isEmpty(dateString)) return null; try { return getFormatterFor(pattern).parse(dateString); } catch (ParseException e) { Timber.e(e, "parsing date string"); return null; } } /* Instance */ /** * The default constructor uses the current time instance by default. */ public MmxDate() { mCalendar = Calendar.getInstance(); } public MmxDate(Calendar calendar) { mCalendar = calendar; } public MmxDate(Date date) { mCalendar = new GregorianCalendar(); if (date != null) { mCalendar.setTime(date); } } /** * Creates a date/time object from an ISO date string. * @param isoString ISO date string */ public MmxDate(@NonNull String isoString) { String pattern = Constants.ISO_DATE_FORMAT; Date date = from(isoString, pattern); mCalendar = new GregorianCalendar(); mCalendar.setTime(date); } public MmxDate(String dateString, String pattern) { Date date = from(dateString, pattern); mCalendar = new GregorianCalendar(); mCalendar.setTime(date); } public MmxDate(int year, int month, int day) { mCalendar = new GregorianCalendar(year, month, day); } public MmxDate(long ticks) { mCalendar = new GregorianCalendar(); mCalendar.setTimeInMillis(ticks); } private Calendar mCalendar; public MmxDate addDays(int value) { mCalendar.add(Calendar.DATE, value); return this; } public MmxDate addMonth(int value) { mCalendar.add(Calendar.MONTH, value); return this; } public MmxDate addYear(int value) { mCalendar.add(Calendar.YEAR, value); return this; } /** * Sets the calendar to the first day of the month to which the calendar points to. * I.e. if the calendar is 2015-08-20, this will return 2015-08-01 00:00:00.000 * @return The first day of the month in which the Calendar is set. */ public MmxDate firstDayOfMonth() { mCalendar.set(Calendar.DAY_OF_MONTH, mCalendar.getActualMinimum(Calendar.DAY_OF_MONTH)); return this; } public MmxDate firstMonthOfYear() { mCalendar.set(Calendar.MONTH, mCalendar.getActualMinimum(Calendar.MONTH)); return this; } public Calendar getCalendar() { return mCalendar; } public int getDayOfMonth() { return mCalendar.get(Calendar.DAY_OF_MONTH); } public int getDayOfWeek() { return mCalendar.get(Calendar.DAY_OF_WEEK); } public int getHour() { return getHourOfDay(); } public int getHourOfDay() { return mCalendar.get(Calendar.HOUR_OF_DAY); } public long getMillis() { return mCalendar.getTimeInMillis(); } public int getMinute() { return getMinuteOfHour(); } public int getMinuteOfHour() { return mCalendar.get(Calendar.MINUTE); } public int getYear() { return mCalendar.get(Calendar.YEAR); } public int getMonth() { return mCalendar.get(Calendar.MONTH); } public int getMonthOfYear() { return getMonth(); } /** * Converts the date/time value to the destination time zone. * @param timeZone The name of the time zone. I.e. "Europe/Berlin". * @return Date/Time value in the destination time zone. */ public MmxDate inTimeZone(String timeZone) { // Keep the original value for conversion. long currentValue = mCalendar.getTimeInMillis(); // now create the calendar in the destination time zone and convert the value. mCalendar = new GregorianCalendar(TimeZone.getTimeZone(timeZone)); mCalendar.setTimeInMillis(currentValue); return this; } public MmxDate lastDayOfMonth() { mCalendar.set(Calendar.DAY_OF_MONTH, mCalendar.getActualMaximum(Calendar.DAY_OF_MONTH)); return this; } public MmxDate lastMonthOfYear() { mCalendar.set(Calendar.MONTH, mCalendar.getActualMaximum(Calendar.MONTH)); return this; } public MmxDate minusDays(int value) { return addDays(-value); } public MmxDate minusMonths(int value) { return addMonth(-value); } public MmxDate minusYears(int value) { return addYear(-value); } public MmxDate plusDays(int value) { return addDays(value); } public MmxDate plusMonths(int value) { return addMonth(value); } public MmxDate plusWeeks(int value) { mCalendar.add(Calendar.WEEK_OF_YEAR, value); return this; } public MmxDate plusYears(int value) { return addYear(value); } public MmxDate setCalendar(Calendar calendar) { mCalendar = calendar; return this; } public MmxDate setDate(int dayOfMonth) { mCalendar.set(Calendar.DAY_OF_MONTH, dayOfMonth); return this; } public MmxDate setHour(int hour) { mCalendar.set(Calendar.HOUR_OF_DAY, hour); return this; } public MmxDate setMinute(int minute) { mCalendar.set(Calendar.MINUTE, minute); return this; } public MmxDate setMilisecond(int milisecond) { mCalendar.set(Calendar.MILLISECOND, milisecond); return this; } /** * Set the month for the current calendar. * @param month Month value i.e. Calendar.January. NOT ordinal, i.e. November != 11. * @return */ public MmxDate setMonth(int month) { mCalendar.set(Calendar.MONTH, month); return this; } public MmxDate setSecond(int second) { mCalendar.set(Calendar.SECOND, second); return this; } public MmxDate setYear(int year) { mCalendar.set(Calendar.YEAR, year); return this; } // public MmxDate setNow() { // mCalendar = Calendar.getInstance(); // return this; // } public MmxDate setTimeToBeginningOfDay() { setHour(0); setMinute(0); setSecond(0); setMilisecond(0); return this; } public MmxDate setTimeToEndOfDay() { Calendar calendar = mCalendar; calendar.set(Calendar.HOUR_OF_DAY, 23); calendar.set(Calendar.MINUTE, 59); calendar.set(Calendar.SECOND, 59); calendar.set(Calendar.MILLISECOND, 999); return this; } public MmxDate setTime(Date date) { mCalendar.setTime(date); return this; } public MmxDate setTimeZone(String timeZone) { mCalendar.setTimeZone(TimeZone.getTimeZone(timeZone)); return this; } public Date toDate() { return mCalendar.getTime(); } public MmxDate today() { return setTimeToBeginningOfDay(); } public String toString(String format) { return getFormatterFor(format).format(toDate()); } public String toIsoString() { // if (date == null) return null; SimpleDateFormat format = new SimpleDateFormat(Constants.ISO_DATE_FORMAT, Locale.ENGLISH); return format.format(toDate()); } /* Private */ private static SimpleDateFormat getFormatterFor(String format) { return new SimpleDateFormat(format, Locale.ENGLISH); } }