/* * Copyright (C) 2016 Álinson Santos Xavier <isoron@gmail.com> * * This file is part of Loop Habit Tracker. * * Loop Habit Tracker 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. * * Loop Habit Tracker 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 org.isoron.uhabits.utils; import android.content.*; import android.text.format.*; import org.isoron.uhabits.*; import java.util.*; import static java.util.Calendar.*; public abstract class DateUtils { private static Long fixedLocalTime = null; private static TimeZone fixedTimeZone = null; /** * Number of milliseconds in one day. */ public static long millisecondsInOneDay = 24 * 60 * 60 * 1000; public static long applyTimezone(long localTimestamp) { TimeZone tz = getTimezone(); long now = new Date(localTimestamp).getTime(); return now - tz.getOffset(now); } public static String formatHeaderDate(GregorianCalendar day) { Locale locale = Locale.getDefault(); String dayOfMonth = Integer.toString(day.get(DAY_OF_MONTH)); String dayOfWeek = day.getDisplayName(DAY_OF_WEEK, SHORT, locale); return dayOfWeek + "\n" + dayOfMonth; } public static String formatTime(Context context, int hours, int minutes) { int reminderMilliseconds = (hours * 60 + minutes) * 60 * 1000; Date date = new Date(reminderMilliseconds); java.text.DateFormat df = DateFormat.getTimeFormat(context); df.setTimeZone(TimeZone.getTimeZone("UTC")); return df.format(date); } public static String formatWeekdayList(Context context, boolean weekday[]) { String shortDayNames[] = getShortDayNames(); String longDayNames[] = getLongDayNames(); StringBuilder buffer = new StringBuilder(); int count = 0; int first = 0; boolean isFirst = true; for (int i = 0; i < 7; i++) { if (weekday[i]) { if (isFirst) first = i; else buffer.append(", "); buffer.append(shortDayNames[i]); isFirst = false; count++; } } if (count == 1) return longDayNames[first]; if (count == 2 && weekday[0] && weekday[1]) return context.getString(R.string.weekends); if (count == 5 && !weekday[0] && !weekday[1]) return context.getString(R.string.any_weekday); if (count == 7) return context.getString(R.string.any_day); return buffer.toString(); } public static GregorianCalendar getCalendar(long timestamp) { GregorianCalendar day = new GregorianCalendar(TimeZone.getTimeZone("GMT")); day.setTimeInMillis(timestamp); return day; } public static String[] getDayNames(int format) { String[] wdays = new String[7]; Calendar day = new GregorianCalendar(); day.set(DAY_OF_WEEK, Calendar.SATURDAY); for (int i = 0; i < wdays.length; i++) { wdays[i] = day.getDisplayName(DAY_OF_WEEK, format, Locale.getDefault()); day.add(DAY_OF_MONTH, 1); } return wdays; } public static long getLocalTime() { if (fixedLocalTime != null) return fixedLocalTime; TimeZone tz = getTimezone(); long now = new Date().getTime(); return now + tz.getOffset(now); } /** * @return array with weekday names starting according to locale settings, * e.g. [Mo,Di,Mi,Do,Fr,Sa,So] in Europe */ public static String[] getLocaleDayNames(int format) { String[] days = new String[7]; Calendar calendar = new GregorianCalendar(); calendar.set(DAY_OF_WEEK, calendar.getFirstDayOfWeek()); for (int i = 0; i < days.length; i++) { days[i] = calendar.getDisplayName(DAY_OF_WEEK, format, Locale.getDefault()); calendar.add(DAY_OF_MONTH, 1); } return days; } /** * @return array with week days numbers starting according to locale * settings, e.g. [2,3,4,5,6,7,1] in Europe */ public static Integer[] getLocaleWeekdayList() { Integer[] dayNumbers = new Integer[7]; Calendar calendar = new GregorianCalendar(); calendar.set(DAY_OF_WEEK, calendar.getFirstDayOfWeek()); for (int i = 0; i < dayNumbers.length; i++) { dayNumbers[i] = calendar.get(DAY_OF_WEEK); calendar.add(DAY_OF_MONTH, 1); } return dayNumbers; } public static String[] getLongDayNames() { return getDayNames(GregorianCalendar.LONG); } public static String[] getShortDayNames() { return getDayNames(SHORT); } public static long getStartOfDay(long timestamp) { return (timestamp / millisecondsInOneDay) * millisecondsInOneDay; } public static long getStartOfToday() { return getStartOfDay(DateUtils.getLocalTime()); } public static long millisecondsUntilTomorrow() { return getStartOfToday() + millisecondsInOneDay - getLocalTime(); } public static GregorianCalendar getStartOfTodayCalendar() { return getCalendar(getStartOfToday()); } public static TimeZone getTimezone() { if(fixedTimeZone != null) return fixedTimeZone; return TimeZone.getDefault(); } public static void setFixedTimeZone(TimeZone tz) { fixedTimeZone = tz; } public static int getWeekday(long timestamp) { GregorianCalendar day = getCalendar(timestamp); return javaWeekdayToLoopWeekday(day.get(DAY_OF_WEEK)); } /** * Throughout the code, it is assumed that the weekdays are numbered from 0 * (Saturday) to 6 (Friday). In the Java Calendar they are numbered from 1 * (Sunday) to 7 (Saturday). This function converts from Java to our * internal representation. * * @return weekday number in the internal interpretation */ public static int javaWeekdayToLoopWeekday(int number) { return number % 7; } public static long removeTimezone(long timestamp) { TimeZone tz = getTimezone(); long now = new Date(timestamp).getTime(); return now + tz.getOffset(now); } public static void setFixedLocalTime(Long timestamp) { fixedLocalTime = timestamp; } public static Long truncate(TruncateField field, long timestamp) { GregorianCalendar cal = DateUtils.getCalendar(timestamp); switch (field) { case MONTH: cal.set(DAY_OF_MONTH, 1); return cal.getTimeInMillis(); case WEEK_NUMBER: int firstWeekday = cal.getFirstDayOfWeek(); int weekday = cal.get(DAY_OF_WEEK); int delta = weekday - firstWeekday; if (delta < 0) delta += 7; cal.add(Calendar.DAY_OF_YEAR, -delta); return cal.getTimeInMillis(); case QUARTER: int quarter = cal.get(Calendar.MONTH) / 3; cal.set(DAY_OF_MONTH, 1); cal.set(Calendar.MONTH, quarter * 3); return cal.getTimeInMillis(); case YEAR: cal.set(Calendar.MONTH, Calendar.JANUARY); cal.set(DAY_OF_MONTH, 1); return cal.getTimeInMillis(); default: throw new IllegalArgumentException(); } } public enum TruncateField { MONTH, WEEK_NUMBER, YEAR, QUARTER } /** * Gets the number of days between two timestamps (exclusively). * * @param t1 the first timestamp to use in milliseconds * @param t2 the second timestamp to use in milliseconds * @return the number of days between the two timestamps */ public static int getDaysBetween(long t1, long t2) { Date d1 = new Date(t1); Date d2 = new Date(t2); return (int) (Math.abs((d2.getTime() - d1.getTime()) / millisecondsInOneDay)); } }