mirror of https://github.com/iSoron/uhabits.git
commit
d279388884
@ -1,333 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.core.utils;
|
|
||||||
|
|
||||||
import androidx.annotation.*;
|
|
||||||
|
|
||||||
import org.isoron.uhabits.core.models.*;
|
|
||||||
import org.jetbrains.annotations.*;
|
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
import static java.util.Calendar.*;
|
|
||||||
|
|
||||||
public abstract class DateUtils
|
|
||||||
{
|
|
||||||
|
|
||||||
private static Long fixedLocalTime = null;
|
|
||||||
|
|
||||||
private static TimeZone fixedTimeZone = null;
|
|
||||||
|
|
||||||
private static Locale fixedLocale = null;
|
|
||||||
|
|
||||||
private static int startDayHourOffset = 0;
|
|
||||||
|
|
||||||
private static int startDayMinuteOffset = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Number of milliseconds in one minute.
|
|
||||||
*/
|
|
||||||
|
|
||||||
public static final long MINUTE_LENGTH = 60 * 1000;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Number of milliseconds in one hour.
|
|
||||||
*/
|
|
||||||
public static final long HOUR_LENGTH = 60 * MINUTE_LENGTH;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Number of milliseconds in one day.
|
|
||||||
*/
|
|
||||||
public static final long DAY_LENGTH = 24 * HOUR_LENGTH;
|
|
||||||
|
|
||||||
public static long applyTimezone(long localTimestamp)
|
|
||||||
{
|
|
||||||
TimeZone tz = getTimezone();
|
|
||||||
return localTimestamp - tz.getOffset(localTimestamp - tz.getOffset(localTimestamp));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String formatHeaderDate(GregorianCalendar day)
|
|
||||||
{
|
|
||||||
Locale locale = getLocale();
|
|
||||||
String dayOfMonth = Integer.toString(day.get(DAY_OF_MONTH));
|
|
||||||
String dayOfWeek = day.getDisplayName(DAY_OF_WEEK, SHORT, locale);
|
|
||||||
return dayOfWeek + "\n" + dayOfMonth;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static GregorianCalendar getCalendar(long timestamp)
|
|
||||||
{
|
|
||||||
GregorianCalendar day =
|
|
||||||
new GregorianCalendar(TimeZone.getTimeZone("GMT"), getLocale());
|
|
||||||
day.setTimeInMillis(timestamp);
|
|
||||||
return day;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static long getLocalTime()
|
|
||||||
{
|
|
||||||
if (fixedLocalTime != null) return fixedLocalTime;
|
|
||||||
|
|
||||||
TimeZone tz = getTimezone();
|
|
||||||
long now = new Date().getTime();
|
|
||||||
return now + tz.getOffset(now);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns an array of strings with the names for each day of the week,
|
|
||||||
* in either SHORT or LONG format. The first entry corresponds to the
|
|
||||||
* first day of the week, according to the provided argument.
|
|
||||||
*
|
|
||||||
* @param format Either GregorianCalendar.SHORT or LONG
|
|
||||||
* @param firstWeekday An integer representing the first day of the week,
|
|
||||||
* following java.util.Calendar conventions. That is,
|
|
||||||
* Saturday corresponds to 7, and Sunday corresponds
|
|
||||||
* to 1.
|
|
||||||
*/
|
|
||||||
@NotNull
|
|
||||||
private static String[] getWeekdayNames(int format, int firstWeekday)
|
|
||||||
{
|
|
||||||
String[] days = new String[7];
|
|
||||||
Calendar calendar = new GregorianCalendar();
|
|
||||||
calendar.set(DAY_OF_WEEK, firstWeekday);
|
|
||||||
for (int i = 0; i < days.length; i++) {
|
|
||||||
days[i] = calendar.getDisplayName(DAY_OF_WEEK, format,
|
|
||||||
getLocale());
|
|
||||||
calendar.add(DAY_OF_MONTH, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
return days;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a vector of exactly seven integers, where the first integer is
|
|
||||||
* the provided firstWeekday number, and each subsequent number is the
|
|
||||||
* previous number plus 1, wrapping back to 1 after 7. For example,
|
|
||||||
* providing 3 as firstWeekday returns {3,4,5,6,7,1,2}
|
|
||||||
*
|
|
||||||
* This function is supposed to be used to construct a sequence of weekday
|
|
||||||
* number following java.util.Calendar conventions.
|
|
||||||
*/
|
|
||||||
public static int[] getWeekdaySequence(int firstWeekday)
|
|
||||||
{
|
|
||||||
return new int[]
|
|
||||||
{
|
|
||||||
(firstWeekday - 1) % 7 + 1,
|
|
||||||
(firstWeekday) % 7 + 1,
|
|
||||||
(firstWeekday + 1) % 7 + 1,
|
|
||||||
(firstWeekday + 2) % 7 + 1,
|
|
||||||
(firstWeekday + 3) % 7 + 1,
|
|
||||||
(firstWeekday + 4) % 7 + 1,
|
|
||||||
(firstWeekday + 5) % 7 + 1,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return An integer representing the first day of the week, according to
|
|
||||||
* the current locale. Sunday corresponds to 1, Monday to 2, and so on,
|
|
||||||
* until Saturday, which is represented by 7. This is consistent
|
|
||||||
* with java.util.Calendar constants.
|
|
||||||
*/
|
|
||||||
public static int getFirstWeekdayNumberAccordingToLocale()
|
|
||||||
{
|
|
||||||
return new GregorianCalendar().getFirstDayOfWeek();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return A vector of strings with the long names for the week days,
|
|
||||||
* according to the current locale. The first entry corresponds to Saturday,
|
|
||||||
* the second entry corresponds to Monday, and so on.
|
|
||||||
*
|
|
||||||
* @param firstWeekday Either Calendar.SATURDAY, Calendar.MONDAY, or other
|
|
||||||
* weekdays defined in this class.
|
|
||||||
*/
|
|
||||||
public static String[] getLongWeekdayNames(int firstWeekday)
|
|
||||||
{
|
|
||||||
return getWeekdayNames(GregorianCalendar.LONG, firstWeekday);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a vector of strings with the short names for the week days,
|
|
||||||
* according to the current locale. The first entry corresponds to Saturday,
|
|
||||||
* the second entry corresponds to Monday, and so on.
|
|
||||||
*
|
|
||||||
* @param firstWeekday Either Calendar.SATURDAY, Calendar.MONDAY, or other
|
|
||||||
* weekdays defined in this class.
|
|
||||||
*/
|
|
||||||
public static String[] getShortWeekdayNames(int firstWeekday)
|
|
||||||
{
|
|
||||||
return getWeekdayNames(GregorianCalendar.SHORT, firstWeekday);
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public static Timestamp getToday()
|
|
||||||
{
|
|
||||||
return new Timestamp(getStartOfToday());
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public static Timestamp getTodayWithOffset()
|
|
||||||
{
|
|
||||||
return new Timestamp(getStartOfTodayWithOffset());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static long getStartOfDay(long timestamp)
|
|
||||||
{
|
|
||||||
return (timestamp / DAY_LENGTH) * DAY_LENGTH;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static long getStartOfDayWithOffset(long timestamp)
|
|
||||||
{
|
|
||||||
long offset = startDayHourOffset * HOUR_LENGTH + startDayMinuteOffset * MINUTE_LENGTH;
|
|
||||||
return getStartOfDay(timestamp - offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static long getStartOfToday()
|
|
||||||
{
|
|
||||||
return getStartOfDay(getLocalTime());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static long getStartOfTomorrowWithOffset()
|
|
||||||
{
|
|
||||||
return getUpcomingTimeInMillis(startDayHourOffset, startDayMinuteOffset);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static long getStartOfTodayWithOffset()
|
|
||||||
{
|
|
||||||
return getStartOfDayWithOffset(getLocalTime());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static long millisecondsUntilTomorrowWithOffset()
|
|
||||||
{
|
|
||||||
return getStartOfTomorrowWithOffset() - getLocalTime();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static GregorianCalendar getStartOfTodayCalendar()
|
|
||||||
{
|
|
||||||
return getCalendar(getStartOfToday());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static GregorianCalendar getStartOfTodayCalendarWithOffset()
|
|
||||||
{
|
|
||||||
return getCalendar(getStartOfTodayWithOffset());
|
|
||||||
}
|
|
||||||
|
|
||||||
private static TimeZone getTimezone()
|
|
||||||
{
|
|
||||||
if(fixedTimeZone != null) return fixedTimeZone;
|
|
||||||
return TimeZone.getDefault();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void setFixedTimeZone(TimeZone tz)
|
|
||||||
{
|
|
||||||
fixedTimeZone = tz;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static long removeTimezone(long timestamp)
|
|
||||||
{
|
|
||||||
TimeZone tz = getTimezone();
|
|
||||||
return timestamp + tz.getOffset(timestamp);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void setFixedLocalTime(Long timestamp)
|
|
||||||
{
|
|
||||||
fixedLocalTime = timestamp;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void setFixedLocale(Locale locale)
|
|
||||||
{
|
|
||||||
fixedLocale = locale;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void setStartDayOffset(int hourOffset, int minuteOffset)
|
|
||||||
{
|
|
||||||
startDayHourOffset = hourOffset;
|
|
||||||
startDayMinuteOffset = minuteOffset;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Locale getLocale()
|
|
||||||
{
|
|
||||||
if(fixedLocale != null) return fixedLocale;
|
|
||||||
return Locale.getDefault();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Timestamp truncate(TruncateField field,
|
|
||||||
Timestamp timestamp,
|
|
||||||
int firstWeekday)
|
|
||||||
{
|
|
||||||
return new Timestamp(truncate(field, timestamp.getUnixTime(), firstWeekday));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Long truncate(TruncateField field,
|
|
||||||
long timestamp,
|
|
||||||
int firstWeekday)
|
|
||||||
{
|
|
||||||
GregorianCalendar cal = DateUtils.getCalendar(timestamp);
|
|
||||||
|
|
||||||
|
|
||||||
switch (field)
|
|
||||||
{
|
|
||||||
case DAY:
|
|
||||||
return cal.getTimeInMillis();
|
|
||||||
|
|
||||||
case MONTH:
|
|
||||||
cal.set(DAY_OF_MONTH, 1);
|
|
||||||
return cal.getTimeInMillis();
|
|
||||||
|
|
||||||
case WEEK_NUMBER:
|
|
||||||
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 static long getUpcomingTimeInMillis(int hour, int minute)
|
|
||||||
{
|
|
||||||
Calendar calendar = DateUtils.getStartOfTodayCalendar();
|
|
||||||
calendar.set(Calendar.HOUR_OF_DAY, hour);
|
|
||||||
calendar.set(Calendar.MINUTE, minute);
|
|
||||||
calendar.set(Calendar.SECOND, 0);
|
|
||||||
long time = calendar.getTimeInMillis();
|
|
||||||
|
|
||||||
if (DateUtils.getLocalTime() > time)
|
|
||||||
time += DateUtils.DAY_LENGTH;
|
|
||||||
|
|
||||||
return applyTimezone(time);
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum TruncateField
|
|
||||||
{
|
|
||||||
DAY, MONTH, WEEK_NUMBER, YEAR, QUARTER
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,331 @@
|
|||||||
|
/*
|
||||||
|
* 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.core.utils
|
||||||
|
|
||||||
|
import org.isoron.uhabits.core.models.Timestamp
|
||||||
|
import java.util.Calendar
|
||||||
|
import java.util.Calendar.DAY_OF_MONTH
|
||||||
|
import java.util.Calendar.DAY_OF_WEEK
|
||||||
|
import java.util.Calendar.SHORT
|
||||||
|
import java.util.Date
|
||||||
|
import java.util.GregorianCalendar
|
||||||
|
import java.util.Locale
|
||||||
|
import java.util.TimeZone
|
||||||
|
|
||||||
|
abstract class DateUtils {
|
||||||
|
companion object {
|
||||||
|
private var fixedLocalTime: Long? = null
|
||||||
|
private var fixedTimeZone: TimeZone? = null
|
||||||
|
private var fixedLocale: Locale? = null
|
||||||
|
private var startDayHourOffset: Int = 0
|
||||||
|
private var startDayMinuteOffset: Int = 0
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Number of milliseconds in one minute.
|
||||||
|
*/
|
||||||
|
const val MINUTE_LENGTH: Long = 60 * 1000
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Number of milliseconds in one hour.
|
||||||
|
*/
|
||||||
|
const val HOUR_LENGTH: Long = 60 * MINUTE_LENGTH
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Number of milliseconds in one day.
|
||||||
|
*/
|
||||||
|
const val DAY_LENGTH: Long = 24 * HOUR_LENGTH
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun applyTimezone(localTimestamp: Long): Long {
|
||||||
|
val tz: TimeZone = getTimeZone()
|
||||||
|
return localTimestamp - tz.getOffset(localTimestamp - tz.getOffset(localTimestamp))
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun formatHeaderDate(day: GregorianCalendar): String {
|
||||||
|
val locale = getLocale()
|
||||||
|
val dayOfMonth: String = day.get(DAY_OF_MONTH).toString()
|
||||||
|
val dayOfWeek = day.getDisplayName(DAY_OF_WEEK, SHORT, locale)
|
||||||
|
return dayOfWeek + "\n" + dayOfMonth
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getCalendar(timestamp: Long): GregorianCalendar {
|
||||||
|
val day = GregorianCalendar(TimeZone.getTimeZone("GMT"), getLocale())
|
||||||
|
day.timeInMillis = timestamp
|
||||||
|
return day
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun getLocalTime(): Long {
|
||||||
|
if (fixedLocalTime != null) return fixedLocalTime as Long
|
||||||
|
|
||||||
|
val tz = getTimeZone()
|
||||||
|
val now = Date().getTime()
|
||||||
|
return now + tz.getOffset(now)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an array of strings with the names for each day of the week,
|
||||||
|
* in either SHORT or LONG format. The first entry corresponds to the
|
||||||
|
* first day of the week, according to the provided argument.
|
||||||
|
*
|
||||||
|
* @param format Either GregorianCalendar.SHORT or LONG
|
||||||
|
* @param firstWeekDay An integer representing the first day of the week,
|
||||||
|
* following java.util.Calendar conventions. That is,
|
||||||
|
* Saturday corresponds to 7, and Sunday corresponds
|
||||||
|
* to 1.
|
||||||
|
*/
|
||||||
|
private fun getWeekdayNames(
|
||||||
|
format: Int,
|
||||||
|
firstWeekDay: Int
|
||||||
|
): Array<String> {
|
||||||
|
val calendar = GregorianCalendar()
|
||||||
|
calendar.set(DAY_OF_WEEK, firstWeekDay)
|
||||||
|
|
||||||
|
val daysNullable = ArrayList<String>()
|
||||||
|
for (i in 1..7) {
|
||||||
|
daysNullable.add(
|
||||||
|
calendar.getDisplayName(
|
||||||
|
DAY_OF_WEEK,
|
||||||
|
format,
|
||||||
|
getLocale()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
calendar.add(DAY_OF_MONTH, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return daysNullable.toTypedArray()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a vector of exactly seven integers, where the first integer is
|
||||||
|
* the provided firstWeekday number, and each subsequent number is the
|
||||||
|
* previous number plus 1, wrapping back to 1 after 7. For example,
|
||||||
|
* providing 3 as firstWeekday returns {3,4,5,6,7,1,2}
|
||||||
|
*
|
||||||
|
* This function is supposed to be used to construct a sequence of weekday
|
||||||
|
* number following java.util.Calendar conventions.
|
||||||
|
*/
|
||||||
|
@JvmStatic
|
||||||
|
fun getWeekdaySequence(firstWeekday: Int): Array<Int> {
|
||||||
|
return arrayOf(
|
||||||
|
(firstWeekday - 1) % 7 + 1,
|
||||||
|
(firstWeekday) % 7 + 1,
|
||||||
|
(firstWeekday + 1) % 7 + 1,
|
||||||
|
(firstWeekday + 2) % 7 + 1,
|
||||||
|
(firstWeekday + 3) % 7 + 1,
|
||||||
|
(firstWeekday + 4) % 7 + 1,
|
||||||
|
(firstWeekday + 5) % 7 + 1,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return An integer representing the first day of the week, according to
|
||||||
|
* the current locale. Sunday corresponds to 1, Monday to 2, and so on,
|
||||||
|
* until Saturday, which is represented by 7. This is consistent
|
||||||
|
* with java.util.Calendar constants.
|
||||||
|
*/
|
||||||
|
@JvmStatic
|
||||||
|
fun getFirstWeekdayNumberAccordingToLocale(): Int {
|
||||||
|
return GregorianCalendar().firstDayOfWeek
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return A vector of strings with the long names for the week days,
|
||||||
|
* according to the current locale. The first entry corresponds to Saturday,
|
||||||
|
* the second entry corresponds to Monday, and so on.
|
||||||
|
*
|
||||||
|
* @param firstWeekday Either Calendar.SATURDAY, Calendar.MONDAY, or other
|
||||||
|
* weekdays defined in this class.
|
||||||
|
*/
|
||||||
|
@JvmStatic
|
||||||
|
fun getLongWeekdayNames(firstWeekday: Int): Array<String> {
|
||||||
|
return getWeekdayNames(GregorianCalendar.LONG, firstWeekday)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a vector of strings with the short names for the week days,
|
||||||
|
* according to the current locale. The first entry corresponds to Saturday,
|
||||||
|
* the second entry corresponds to Monday, and so on.
|
||||||
|
*
|
||||||
|
* @param firstWeekday Either Calendar.SATURDAY, Calendar.MONDAY, or other
|
||||||
|
* weekdays defined in this class.
|
||||||
|
*/
|
||||||
|
@JvmStatic
|
||||||
|
fun getShortWeekdayNames(firstWeekday: Int): Array<String> {
|
||||||
|
return getWeekdayNames(GregorianCalendar.SHORT, firstWeekday)
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun getToday(): Timestamp = Timestamp(getStartOfToday())
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun getTodayWithOffset(): Timestamp = Timestamp(getStartOfTodayWithOffset())
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun getStartOfDay(timestamp: Long): Long = (timestamp / DAY_LENGTH) * DAY_LENGTH
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun getStartOfDayWithOffset(timestamp: Long): Long {
|
||||||
|
val offset = startDayHourOffset * HOUR_LENGTH + startDayMinuteOffset * MINUTE_LENGTH
|
||||||
|
return getStartOfDay(timestamp - offset)
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun getStartOfToday(): Long = getStartOfDay(getLocalTime())
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun getStartOfTomorrowWithOffset(): Long = getUpcomingTimeInMillis(
|
||||||
|
startDayHourOffset,
|
||||||
|
startDayMinuteOffset
|
||||||
|
)
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun getStartOfTodayWithOffset(): Long = getStartOfDayWithOffset(getLocalTime())
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun millisecondsUntilTomorrowWithOffset(): Long = getStartOfTomorrowWithOffset() - getLocalTime()
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun getStartOfTodayCalendar(): GregorianCalendar = getCalendar(getStartOfToday())
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun getStartOfTodayCalendarWithOffset(): GregorianCalendar = getCalendar(getStartOfTodayWithOffset())
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun getTimeZone(): TimeZone {
|
||||||
|
return fixedTimeZone ?: TimeZone.getDefault()
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun getTimezone(): TimeZone {
|
||||||
|
return fixedTimeZone ?: TimeZone.getDefault()
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun removeTimezone(timestamp: Long): Long {
|
||||||
|
val tz = getTimeZone()
|
||||||
|
return timestamp + tz.getOffset(timestamp)
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun setStartDayOffset(hourOffset: Int, minuteOffset: Int) {
|
||||||
|
startDayHourOffset = hourOffset
|
||||||
|
startDayMinuteOffset = minuteOffset
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun getLocale(): Locale {
|
||||||
|
return fixedLocale ?: Locale.getDefault()
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun truncate(
|
||||||
|
field: TruncateField,
|
||||||
|
timestamp: Timestamp,
|
||||||
|
firstWeekday: Int
|
||||||
|
): Timestamp {
|
||||||
|
return Timestamp(
|
||||||
|
truncate(
|
||||||
|
field,
|
||||||
|
timestamp.unixTime,
|
||||||
|
firstWeekday
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun truncate(
|
||||||
|
field: TruncateField,
|
||||||
|
timestamp: Long,
|
||||||
|
firstWeekday: Int
|
||||||
|
): Long {
|
||||||
|
val cal = getCalendar(timestamp)
|
||||||
|
|
||||||
|
return when (field) {
|
||||||
|
|
||||||
|
TruncateField.DAY -> { cal.timeInMillis }
|
||||||
|
|
||||||
|
TruncateField.MONTH -> {
|
||||||
|
cal.set(DAY_OF_MONTH, 1)
|
||||||
|
cal.timeInMillis
|
||||||
|
}
|
||||||
|
|
||||||
|
TruncateField.WEEK_NUMBER -> {
|
||||||
|
val weekDay = cal.get(DAY_OF_WEEK)
|
||||||
|
var delta = weekDay - firstWeekday
|
||||||
|
if (delta < 0) { delta += 7 }
|
||||||
|
cal.add(Calendar.DAY_OF_YEAR, -delta)
|
||||||
|
cal.timeInMillis
|
||||||
|
}
|
||||||
|
|
||||||
|
TruncateField.QUARTER -> {
|
||||||
|
val quarter = cal.get(Calendar.MONTH) / 3
|
||||||
|
cal.set(DAY_OF_MONTH, 1)
|
||||||
|
cal.set(Calendar.MONTH, quarter * 3)
|
||||||
|
cal.timeInMillis
|
||||||
|
}
|
||||||
|
|
||||||
|
TruncateField.YEAR -> {
|
||||||
|
cal.set(Calendar.MONTH, Calendar.JANUARY)
|
||||||
|
cal.set(DAY_OF_MONTH, 1)
|
||||||
|
cal.timeInMillis
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun getUpcomingTimeInMillis(
|
||||||
|
hour: Int,
|
||||||
|
minute: Int
|
||||||
|
): Long {
|
||||||
|
val calendar = getStartOfTodayCalendar()
|
||||||
|
calendar.set(Calendar.HOUR_OF_DAY, hour)
|
||||||
|
calendar.set(Calendar.MINUTE, minute)
|
||||||
|
calendar.set(Calendar.SECOND, 0)
|
||||||
|
var time = calendar.timeInMillis
|
||||||
|
|
||||||
|
if (getLocalTime() > time) {
|
||||||
|
time += DAY_LENGTH
|
||||||
|
}
|
||||||
|
|
||||||
|
return applyTimezone(time)
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun setFixedLocalTime(newFixedLocalTime: Long?) {
|
||||||
|
this.fixedLocalTime = newFixedLocalTime
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun setFixedTimeZone(newTimeZone: TimeZone?) {
|
||||||
|
this.fixedTimeZone = newTimeZone
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun setFixedLocale(newLocale: Locale?) {
|
||||||
|
this.fixedLocale = newLocale
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class TruncateField {
|
||||||
|
DAY, MONTH, WEEK_NUMBER, YEAR, QUARTER
|
||||||
|
}
|
||||||
|
}
|
@ -1,77 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2017 Á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.core.utils;
|
|
||||||
|
|
||||||
import org.isoron.uhabits.core.*;
|
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
import java.util.concurrent.*;
|
|
||||||
|
|
||||||
import javax.inject.*;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A class that emits events when a new day starts.
|
|
||||||
*/
|
|
||||||
@AppScope
|
|
||||||
public class MidnightTimer
|
|
||||||
{
|
|
||||||
private final List<MidnightListener> listeners;
|
|
||||||
|
|
||||||
private ScheduledExecutorService executor;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
public MidnightTimer()
|
|
||||||
{
|
|
||||||
this.listeners = new LinkedList<>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public synchronized void addListener(MidnightListener listener)
|
|
||||||
{
|
|
||||||
this.listeners.add(listener);
|
|
||||||
}
|
|
||||||
|
|
||||||
public synchronized void onPause()
|
|
||||||
{
|
|
||||||
executor.shutdownNow();
|
|
||||||
}
|
|
||||||
|
|
||||||
public synchronized void onResume()
|
|
||||||
{
|
|
||||||
executor = Executors.newSingleThreadScheduledExecutor();
|
|
||||||
executor.scheduleAtFixedRate(() -> notifyListeners(),
|
|
||||||
DateUtils.millisecondsUntilTomorrowWithOffset() + 1000,
|
|
||||||
DateUtils.DAY_LENGTH, TimeUnit.MILLISECONDS);
|
|
||||||
}
|
|
||||||
|
|
||||||
public synchronized void removeListener(MidnightListener listener)
|
|
||||||
{
|
|
||||||
this.listeners.remove(listener);
|
|
||||||
}
|
|
||||||
|
|
||||||
private synchronized void notifyListeners()
|
|
||||||
{
|
|
||||||
for (MidnightListener l : listeners) l.atMidnight();
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface MidnightListener
|
|
||||||
{
|
|
||||||
void atMidnight();
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,63 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2017 Á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.core.utils
|
||||||
|
|
||||||
|
import org.isoron.uhabits.core.AppScope
|
||||||
|
import java.util.LinkedList
|
||||||
|
import java.util.concurrent.Executors
|
||||||
|
import java.util.concurrent.ScheduledExecutorService
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A class that emits events when a new day starts.
|
||||||
|
*/
|
||||||
|
@AppScope
|
||||||
|
open class MidnightTimer @Inject constructor() {
|
||||||
|
private val listeners: MutableList<MidnightListener> = LinkedList()
|
||||||
|
private lateinit var executor: ScheduledExecutorService
|
||||||
|
|
||||||
|
@Synchronized fun addListener(listener: MidnightListener) {
|
||||||
|
this.listeners.add(listener)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Synchronized fun onPause() = executor.shutdownNow()
|
||||||
|
|
||||||
|
@Synchronized fun onResume() {
|
||||||
|
executor = Executors.newSingleThreadScheduledExecutor()
|
||||||
|
executor.scheduleAtFixedRate(
|
||||||
|
{ notifyListeners() },
|
||||||
|
DateUtils.millisecondsUntilTomorrowWithOffset() + 1000,
|
||||||
|
DateUtils.DAY_LENGTH,
|
||||||
|
TimeUnit.MILLISECONDS
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Synchronized fun removeListener(listener: MidnightListener) = this.listeners.remove(listener)
|
||||||
|
|
||||||
|
@Synchronized private fun notifyListeners() {
|
||||||
|
for (l in listeners) {
|
||||||
|
l.atMidnight()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface MidnightListener {
|
||||||
|
fun atMidnight()
|
||||||
|
}
|
||||||
|
}
|
@ -1,67 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2017 Á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.core.utils;
|
|
||||||
|
|
||||||
import org.apache.commons.lang3.builder.*;
|
|
||||||
|
|
||||||
import java.math.*;
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
public class StringUtils
|
|
||||||
{
|
|
||||||
private static StandardToStringStyle toStringStyle = null;
|
|
||||||
|
|
||||||
public static String getRandomId()
|
|
||||||
{
|
|
||||||
return new BigInteger(260, new Random()).toString(32).substring(0, 32);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ToStringStyle defaultToStringStyle()
|
|
||||||
{
|
|
||||||
if (toStringStyle == null)
|
|
||||||
{
|
|
||||||
toStringStyle = new StandardToStringStyle();
|
|
||||||
toStringStyle.setFieldSeparator(", ");
|
|
||||||
toStringStyle.setUseClassName(false);
|
|
||||||
toStringStyle.setUseIdentityHashCode(false);
|
|
||||||
toStringStyle.setContentStart("{");
|
|
||||||
toStringStyle.setContentEnd("}");
|
|
||||||
toStringStyle.setFieldNameValueSeparator(": ");
|
|
||||||
toStringStyle.setArrayStart("[");
|
|
||||||
toStringStyle.setArrayEnd("]");
|
|
||||||
}
|
|
||||||
|
|
||||||
return toStringStyle;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String joinLongs(long values[])
|
|
||||||
{
|
|
||||||
return org.apache.commons.lang3.StringUtils.join(values, ',');
|
|
||||||
}
|
|
||||||
|
|
||||||
public static long[] splitLongs(String str)
|
|
||||||
{
|
|
||||||
String parts[] = org.apache.commons.lang3.StringUtils.split(str, ',');
|
|
||||||
|
|
||||||
long numbers[] = new long[parts.length];
|
|
||||||
for (int i = 0; i < parts.length; i++) numbers[i] = Long.valueOf(parts[i]);
|
|
||||||
return numbers;
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,69 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2017 Á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.core.utils
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.builder.StandardToStringStyle
|
||||||
|
import org.apache.commons.lang3.builder.ToStringStyle
|
||||||
|
import java.math.BigInteger
|
||||||
|
import java.util.Random
|
||||||
|
|
||||||
|
class StringUtils {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private lateinit var toStringStyle: StandardToStringStyle
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun getRandomId(): String {
|
||||||
|
return BigInteger(260, Random()).toString(32).subSequence(0, 32).toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun defaultToStringStyle(): ToStringStyle {
|
||||||
|
toStringStyle = StandardToStringStyle()
|
||||||
|
toStringStyle.apply {
|
||||||
|
fieldSeparator = ", "
|
||||||
|
isUseClassName = false
|
||||||
|
isUseIdentityHashCode = false
|
||||||
|
contentStart = "{"
|
||||||
|
contentEnd = "}"
|
||||||
|
fieldNameValueSeparator = ": "
|
||||||
|
arrayStart = "["
|
||||||
|
arrayEnd = "]"
|
||||||
|
}
|
||||||
|
|
||||||
|
return toStringStyle
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun joinLongs(values: LongArray): String {
|
||||||
|
return org.apache.commons.lang3.StringUtils.join(values, ',')
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun splitLongs(str: String): LongArray {
|
||||||
|
val parts: Array<String> = org.apache.commons.lang3.StringUtils.split(str, ',')
|
||||||
|
val numbers = LongArray(parts.size) {
|
||||||
|
i ->
|
||||||
|
parts[i].toLong()
|
||||||
|
}
|
||||||
|
return numbers
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in new issue