at.jclehner.rxdroid.util.DateTime.java Source code

Java tutorial

Introduction

Here is the source code for at.jclehner.rxdroid.util.DateTime.java

Source

/**
 * RxDroid - A Medication Reminder
 * Copyright (C) 2011-2014 Joseph Lehner <joseph.c.lehner@gmail.com>
 *
 *
 * RxDroid 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. Additional terms apply (see LICENSE).
 *
 * RxDroid 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 RxDroid.  If not, see <http://www.gnu.org/licenses/>.
 *
 *
 */

package at.jclehner.rxdroid.util;

import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.Locale;
import java.util.TimeZone;

import android.text.format.DateFormat;
import android.util.Log;

import org.joda.time.LocalDate;

import at.jclehner.rxdroid.DumbTime;
import at.jclehner.rxdroid.PerThreadInstance;
import at.jclehner.rxdroid.RxDroid;

/**
 * Date/time utilities.
 *
 * @author Joseph Lehner
 */
public final class DateTime {
    private static final String TAG = DateTime.class.getSimpleName();
    private static final boolean LOGV = false;

    private static final int[] CALENDAR_TIME_FIELDS = { Calendar.HOUR_OF_DAY, Calendar.MINUTE, Calendar.SECOND,
            Calendar.MILLISECOND };

    private static final String DATE_AND_TIME_FORMAT = "yyyy-MM-dd, HH:mm:ss";
    private static final String DATE_FORMAT = "yyyy-MM-dd";

    private static final HashMap<Long, DateCacheData> DATE_CACHE = new HashMap<Long, DateCacheData>();
    private static boolean sDateCacheEnabled = true;

    public static Calendar calendarFromDate(Date date) {
        final Calendar cal = GregorianCalendar.getInstance();
        cal.setTime(date);
        return cal;
    }

    /**
     * Returns the current date.
     *
     * @return a <code>Calendar</code> set to the current date, its time
     *     set to 00:00:00
     * @deprecated Use {@link #today()}
     */
    @Deprecated
    public static Calendar todayCalendarMutable() {
        return getDatePartMutable(DateTime.nowCalendarMutable());
    }

    public static Date today() {
        final long now = System.currentTimeMillis();
        final long today = now - (now % Constants.MILLIS_PER_DAY);

        return obtainImmutableCachedDateInstance(today).date;
    }

    public static Date yesterday() {
        return DateTime.add(DateTime.today(), Calendar.DAY_OF_MONTH, -1);
    }

    /**
     * Returns the current time.
     *
     * @return the result of <code>Gregorian.getInstance()</code>
     * @deprecated Use {@link #now()}
     */
    @Deprecated
    public static Calendar nowCalendarMutable() {
        return GregorianCalendar.getInstance();
    }

    public static Calendar nowCalendar() {
        return new ImmutableGregorianCalendar(System.currentTimeMillis());
    }

    public static Date now() {
        return nowCalendar().getTime();
    }

    public static Date min(Date date1, Date date2) {
        if (date1 != null && date2 != null)
            return date1.before(date2) ? date1 : date2;
        else if (date1 != null)
            return date1;
        else if (date2 != null)
            return date2;

        return null;
    }

    public static Date max(Date date1, Date date2) {
        if (date1 != null && date2 != null)
            return date1.after(date2) ? date1 : date2;
        else if (date1 != null)
            return date1;
        else if (date2 != null)
            return date2;

        return null;
    }

    /**
     * Sets a <code>Calendar's</code> time to 00:00:00.000.
     */
    public static Calendar getDatePartMutable(Calendar time) {
        final int year = time.get(Calendar.YEAR);
        final int month = time.get(Calendar.MONTH);
        final int day = time.get(Calendar.DAY_OF_MONTH);

        //final Calendar date = (Calendar) time.clone();
        final Calendar date = new GregorianCalendar(year, month, day);
        date.setTimeZone(time.getTimeZone());

        //for(int field: CALENDAR_TIME_FIELDS)
        //   date.set(field, 0);

        return date;
    }

    public static Calendar getDatePart(Calendar time) {
        final ImmutableGregorianCalendar date = getImmutableInstance(time);

        for (int field : CALENDAR_TIME_FIELDS)
            date.setInternal(field, 0);

        return date;
    }

    /**
     * Returns a <code>Calendar</code> with the specified date.
     *
     * @param year The year
     * @param month The month (January is 0, December is 11!)
     * @param day The date
     */
    public static Date date(int year, int month, int day) {
        return calendar(year, month, day).getTime();
    }

    public static Calendar calendar(int year, int month, int day) {
        final Calendar cal = GregorianCalendar.getInstance();
        cal.set(Calendar.HOUR_OF_DAY, 0);
        cal.set(Calendar.MINUTE, 0);
        cal.set(Calendar.SECOND, 0);
        cal.set(Calendar.MILLISECOND, 0);

        cal.set(Calendar.YEAR, year);
        cal.set(Calendar.MONTH, month);
        cal.set(Calendar.DAY_OF_MONTH, day);

        return cal;
    }

    @SuppressWarnings("deprecation")
    public static boolean equalsDate(Date date1, Date date2) {
        if (date1 == null || date2 == null)
            return date1 == date2;

        if (date1.getDate() != date2.getDate())
            return false;

        if (date1.getMonth() != date2.getMonth())
            return false;

        if (date1.getYear() != date2.getYear())
            return false;

        return true;
    }

    public static String toString(Calendar calendar) {
        if (calendar == null)
            return "null";

        SimpleDateFormat sdf = PerThreadInstance.get(SimpleDateFormat.class, DATE_AND_TIME_FORMAT);
        return sdf.format(calendar.getTime());
    }

    public static String toString(long timeInMillis) {
        SimpleDateFormat sdf = PerThreadInstance.get(SimpleDateFormat.class, DATE_AND_TIME_FORMAT);
        return sdf.format(new Date(timeInMillis));
    }

    public static String toDateString(Date date) {
        if (date == null)
            return null;

        SimpleDateFormat sdf = PerThreadInstance.get(SimpleDateFormat.class, DATE_FORMAT);
        return sdf.format(date);
    }

    public static String toNativeDate(Date date) {
        return DateFormat.getDateFormat(RxDroid.getContext()).format(date);
    }

    public static String toNativeDateAndTime(Date date) {
        return DateFormat.getDateFormat(RxDroid.getContext()).format(date) + ", "
                + DateFormat.getTimeFormat(RxDroid.getContext()).format(date);
    }

    public static String toNativeTime(DumbTime time) {
        return time.toString(DateFormat.is24HourFormat(RxDroid.getContext()), false);
    }

    public static String toNativeTime(Date time, boolean withSeconds) {
        final boolean use24HourTime = DateFormat.is24HourFormat(RxDroid.getContext());
        final StringBuilder pattern = new StringBuilder();

        if (use24HourTime)
            pattern.append("HH");
        else
            pattern.append("h");

        pattern.append(":mm");

        if (withSeconds)
            pattern.append(":ss");

        if (!use24HourTime)
            pattern.append(" aa");

        final SimpleDateFormat sdf = new SimpleDateFormat(pattern.toString());
        //sdf.setTimeZone(TimeZone.getTimeZone(("UTC")));
        return sdf.format(time);
    }

    public static long getOffsetFromMidnight(Calendar date) {
        final int hour = date.get(Calendar.HOUR_OF_DAY);
        final int minute = date.get(Calendar.MINUTE);
        final int second = date.get(Calendar.SECOND);
        final int millis = date.get(Calendar.MILLISECOND);

        return millis + 1000 * (hour * 3600 + minute * 60 + second);
    }

    public static long getOffsetFromMidnight(Date date) {
        final Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        return getOffsetFromMidnight(cal);
    }

    public static Date getMidnightDate(Date date) {
        return new Date(date.getTime() - getOffsetFromMidnight(date));
    }

    public static boolean isWithinRange(Calendar time, DumbTime begin, DumbTime end) {
        final DumbTime theTime = DumbTime.fromCalendar(time);

        if (end.isLessThan(begin))
            return theTime.isLessThan(end) || theTime.compareTo(begin) != -1;

        return theTime.compareTo(begin) != -1 && theTime.isLessThan(end);
    }

    public static boolean isToday(Date date) {
        return today().equals(date);
    }

    public static Date add(Date date, int field, int value) {
        if (field == Calendar.DAY_OF_MONTH)
            return new LocalDate(date).plusDays(value).toDate();

        Calendar cal = calendarFromDate(date);
        cal.add(field, value);
        return cal.getTime();
    }

    public static int get(Date date, int field) {
        return calendarFromDate(date).get(field);
    }

    public static Calendar copy(Calendar cal) {
        final GregorianCalendar copy = new GregorianCalendar(cal.getTimeZone());
        copy.setTimeInMillis(cal.getTimeInMillis());
        return copy;
    }

    public static long diffDays(Date date1, Date date2) {
        return Math.round((date2.getTime() - date1.getTime()) / (double) Constants.MILLIS_PER_DAY);
    }

    public static int getIsoWeekDayNumberIndex(Date date) {
        final Calendar cal = calendarFromDate(date);
        return CollectionUtils.indexOf(cal.get(Calendar.DAY_OF_WEEK), Constants.WEEK_DAYS);
    }

    public static void disableDateCache() {
        sDateCacheEnabled = false;
        clearDateCache();
    }

    public static void clearDateCache() {
        DATE_CACHE.clear();
    }

    private static ImmutableGregorianCalendar getImmutableInstance(Calendar cal) {
        final ImmutableGregorianCalendar r = new ImmutableGregorianCalendar(cal);
        r.setTimeInMillisInternal(cal.getTimeInMillis());
        return r;
    }

    private static DateCacheData obtainImmutableCachedDateInstance(long timeInMillis) {
        synchronized (DATE_CACHE) {
            //ImmutableGregorianCalendar instance = DATE_CACHE.get(timeInMillis);
            DateCacheData data = sDateCacheEnabled ? DATE_CACHE.get(timeInMillis) : null;

            if (data == null) {
                data = new DateCacheData();
                data.calendar = new ImmutableGregorianCalendar(timeInMillis);

                for (int field : CALENDAR_TIME_FIELDS)
                    data.calendar.setInternal(field, 0);

                data.date = new ImmutableDate(data.calendar.getTimeInMillis());

                if (sDateCacheEnabled)
                    DATE_CACHE.put(timeInMillis, data);
            } else if (LOGV) {
                if ((++ImmutableGregorianCalendar.sCacheHits % 10) == 0)
                    Log.v(TAG, ImmutableGregorianCalendar.sCacheHits + " cache hits while obtaining current date");
            }

            return data;
        }
    }

    private static final class ImmutableGregorianCalendar extends GregorianCalendar {
        private static final long serialVersionUID = -3883494047745731717L;

        //      private static final SparseArray<ImmutableGregorianCalendar> DATE_CACHE =
        //         new SparseArray<DateTime.ImmutableGregorianCalendar>();

        private static int sCacheHits = 0;

        private ImmutableGregorianCalendar(Calendar other) {
            super(other.getTimeZone(), Locale.getDefault());
            init(other.getTimeInMillis());
        }

        private ImmutableGregorianCalendar(long timeInMillis) {
            super(TimeZone.getDefault(), Locale.getDefault());
            init(timeInMillis);
        }

        @Override
        public void add(int field, int value) {
            throw new UnsupportedOperationException();
        }

        @Override
        public void set(int field, int value) {
            throw new UnsupportedOperationException();
        }

        @Override
        public void roll(int field, boolean increment) {
            throw new UnsupportedOperationException();
        }

        @Override
        public void setTimeInMillis(long milliseconds) {
            if (!isTimeSet) {
                super.setTimeInMillis(milliseconds);
                return;
            }

            throw new UnsupportedOperationException();
        }

        @Override
        public void setTimeZone(TimeZone timezone) {
            if (getTimeZone() == null) {
                super.setTimeZone(timezone);
                return;
            }

            throw new UnsupportedOperationException();
        }

        private void setInternal(int field, int value) {
            super.set(field, value);
        }

        @SuppressWarnings("unused")
        private void setTimeZoneInternal(TimeZone timezone) {
            super.setTimeZone(timezone);
        }

        private void setTimeInMillisInternal(long milliseconds) {
            super.setTimeInMillis(milliseconds);
        }

        private void init(long timeInMillis) {
            time = timeInMillis;
            areFieldsSet = true;
            isTimeSet = true;
            complete();
        }
    }

    private static final class ImmutableDate extends Date {
        private static final long serialVersionUID = -660796950979760891L;
        private boolean mIsTimeSet = false;

        @SuppressWarnings("unused")
        public ImmutableDate(Date date) {
            setTime(date.getTime());
        }

        public ImmutableDate(long timeInMillis) {
            setTime(timeInMillis);
        }

        @Override
        public void setTime(long milliseconds) {
            if (!mIsTimeSet) {
                super.setTime(milliseconds);
                mIsTimeSet = true;
            } else
                throw new UnsupportedOperationException();
        }

        @Override
        public void setSeconds(int second) {
            throw new UnsupportedOperationException();
        }

        @Override
        public void setMinutes(int minute) {
            throw new UnsupportedOperationException();
        }

        @Override
        public void setHours(int hour) {
            throw new UnsupportedOperationException();
        }

        @Override
        public void setDate(int date) {
            throw new UnsupportedOperationException();
        }

        @Override
        public void setMonth(int month) {
            throw new UnsupportedOperationException();
        }

        @Override
        public void setYear(int year) {
            throw new UnsupportedOperationException();
        }
    }

    private static final class DateCacheData {
        ImmutableGregorianCalendar calendar;
        Date date;
    }
}