com.opsmatters.core.util.DateUtilities Maven / Gradle / Ivy
/*
* Copyright 2018 Gerald Curley
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.opsmatters.core.util;
import java.util.List;
import java.util.Calendar;
import java.util.TimeZone;
import java.util.SimpleTimeZone;
import java.util.Locale;
import java.util.Date;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.commons.lang3.LocaleUtils;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
/**
* A set of utility methods to perform miscellaneous tasks related to dates and calendars.
*
* @author Gerald Curley (opsmatters)
*/
public class DateUtilities
{
/**
* The default timezone.
*/
public static final String DEFAULT_TIMEZONE = "Europe/London";
/**
* The default country.
*/
public static final String DEFAULT_COUNTRY = "GB";
/**
* The default timezone.
*/
public static final TimeZone defaultTZ = new SimpleTimeZone(0, "");
/**
* The current timezone.
*/
public static TimeZone currentTZ = null;
/**
* The current locale.
*/
public static Locale currentLocale = null;
/**
* The cache of locale data.
*/
private static final ConcurrentMap localeData = new ConcurrentHashMap(3);
/**
* The name of the BST time zone.
*/
public static final String BST_TZ = "GMT0BST";
public static SimpleTimeZone tzBST;
static
{
// Set up the default GMT0BST time zone
tzBST = new SimpleTimeZone(0, // no offset from GMT
BST_TZ, // individualized tz id
Calendar.MARCH,-1,Calendar.SUNDAY,1*60*60*1000, // last Sun Mar 1AM
Calendar.OCTOBER,-1,Calendar.SUNDAY,2*60*60*1000); // last Sun Oct 2AM
}
/**
* Private constructor as this class shouldn't be instantiated.
*/
private DateUtilities()
{
}
/**
* Returns true
if the given date is inside the start and end hours.
* @param dt The date to be checked
* @param tz The timezone associated with the date
* @param from The start hour to check that the date is after
* @param to The end hour to check that the date is before
* @param tolerance The tolerance that by the which the date can be outside the range but still be considered inside
* @return true
if the given date is inside the start and end hours
*/
public static boolean isBetweenHours(long dt, TimeZone tz, int from, int to, int tolerance)
{
long start = 0L;
long end = 0L;
// If from > to then the "to" date may be in the next day
// or the "from" date may be in the previous day, depending
// on whether or not it's before or after midnight
if(from > to)
{
// Assume that start is in today and end is in tomorrow
start = getDateForHour(dt, tz, from, 0);
end = getDateForHour(dt, tz, to, 1)+(tolerance*1000L);
// If we end up before the start date,
// try moving the dates back by a day
if(dt < start) // move start to yesterday
{
start = getDateForHour(dt, tz, from, -1);
end = getDateForHour(dt, tz, to, 0)+(tolerance*1000L);
}
}
else // to > from
{
start = getDateForHour(dt, tz, from, 0);
end = getDateForHour(dt, tz, to, 0)+(tolerance*1000L);
}
return dt >= start && dt <= end;
}
/**
* Returns true
if the current date is inside the start and end hours.
* @param from The start hour to check that the date is after
* @param to The end hour to check that the date is before
* @return true
if the current date is inside the start and end hours
*/
public static boolean isBetweenHours(int from, int to)
{
return isBetweenHours(System.currentTimeMillis(), currentTZ, from, to, 0);
}
/**
* Returns true
if the current date is inside the start and end hours.
* @param from The start hour to check that the date is after
* @param to The end hour to check that the date is before
* @param tz The timezone associated with the date
* @return true
if the current date is inside the start and end hours
*/
public static boolean isBetweenHours(int from, int to, TimeZone tz)
{
return isBetweenHours(System.currentTimeMillis(), tz, from, to, 0);
}
/**
* Returns true
if the given date is inside the start and end hours.
* @param dt The date to be checked
* @param from The start hour to check that the date is after
* @param to The end hour to check that the date is before
* @param tz The timezone associated with the date
* @return true
if the given date is inside the start and end hours
*/
public static boolean isBetweenHours(long dt, TimeZone tz, int from, int to)
{
return isBetweenHours(dt, tz, from, to, 0);
}
/**
* Returns the date for the given hour.
* @param dt The date to be checked
* @param tz The timezone associated with the date
* @param hour The hour to be checked
* @param dayoffset The day of the month to offset
* @return The date for the given hour
*/
private static long getDateForHour(long dt, TimeZone tz, int hour, int dayoffset)
{
Calendar c = getCalendar(tz);
c.setTimeInMillis(dt);
int dd = c.get(Calendar.DAY_OF_MONTH);
int mm = c.get(Calendar.MONTH);
int yy = c.get(Calendar.YEAR);
c.set(yy, mm, dd, hour, 0, 0);
c.set(Calendar.MILLISECOND, 0);
if(dayoffset != 0)
c.add(Calendar.DAY_OF_MONTH, dayoffset);
return c.getTimeInMillis();
}
/**
* Returns a new calendar object using the given timezone and locale.
* @param tz The timezone associated with the new calendar
* @param locale The locale associated with the new calendar
* @return A new calendar object for the given timezone and locale
*/
public static Calendar getCalendar(TimeZone tz, Locale locale)
{
if(tz == null)
tz = getCurrentTimeZone();
if(locale == null)
locale = getCurrentLocale();
return Calendar.getInstance(tz, locale);
}
/**
* Returns a new calendar object using the given timezone and default locale.
* @param tz The timezone associated with the new calendar
* @return A new calendar object for the given timezone
*/
public static Calendar getCalendar(TimeZone tz)
{
return getCalendar(tz, null);
}
/**
* Returns a new calendar object in the current timezone and default locale.
* @return A new calendar object for the current timezone
*/
public static Calendar getCalendar()
{
return getCalendar(null, null);
}
/**
* Returns the current time zone.
* @return The current time zone
*/
public static TimeZone getCurrentTimeZone()
{
if(currentTZ == null)
setCurrentTimeZone(getUserTimeZone());
return currentTZ;
}
/**
* Sets the current time zone.
* @param tz The current time zone to set
*/
public static void setCurrentTimeZone(TimeZone tz)
{
currentTZ = tz;
}
/**
* Returns the current configured time zone.
*
* Converts GMT to British Summer Time (BST) so that it uses Daylight Savings.
* @return The current configured time zone
*/
public static TimeZone getUserTimeZone()
{
TimeZone ret = null;
// First try the configured timezone
String tz = DEFAULT_TIMEZONE;
ret = AppTimeZone.getTimeZoneById(tz);
if(ret == null)
{
// Next try the locale timezone
tz = System.getProperty("user.timezone");
// Next try the default timezone
if(tz == null || tz.length() == 0)
ret = TimeZone.getDefault();
else if(tz.equals("GMT"))
ret = tzBST; // Use BST instead of GMT
else
ret = TimeZone.getTimeZone(tz); // Otherwise use the standard TZ
}
return ret;
}
/**
* Returns the current locale.
* @return The current configured locale
*/
public static Locale getCurrentLocale()
{
if(currentLocale == null)
setCurrentLocale(getUserLocale());
return currentLocale;
}
/**
* Sets the current locale.
* @param locale The current configured locale to set
*/
public static void setCurrentLocale(Locale locale)
{
currentLocale = locale;
}
/**
* Returns the locale for the current country.
* @return The locale for the current country
*/
public static Locale getUserLocale()
{
String country = System.getProperty("user.country");
return getLocale(country);
}
/**
* Returns the country from the default locale.
* @return The current country from the default locale
*/
public static String getCurrentCountry()
{
return getCurrentLocale().getCountry();
}
/**
* Returns the locale for the given country.
* @param country The country for the locale
* @return The locale for the given country
*/
public static Locale getLocale(String country)
{
if(country == null || country.length() == 0)
country = Locale.getDefault().getCountry();
List locales = LocaleUtils.languagesByCountry(country);
Locale locale = Locale.getDefault();
if(locales.size() > 0)
locale = locales.get(0); // Use the first locale that matches the country
return locale;
}
/**
* Set the attributes of the given calendar from the given locale.
* @param calendar The calendar to set the date settings on
* @param locale The locale to use for the date settings
*/
public static void setCalendarData(Calendar calendar, Locale locale)
{
int[] array = (int[])localeData.get(locale);
if(array == null)
{
Calendar c = Calendar.getInstance(locale);
array = new int[2];
array[0] = c.getFirstDayOfWeek();
array[1] = c.getMinimalDaysInFirstWeek();
localeData.putIfAbsent(locale, array);
}
calendar.setFirstDayOfWeek(array[0]);
calendar.setMinimalDaysInFirstWeek(array[1]);
}
/**
* Returns the given date adding the given number of days.
* @param dt The date to add the days to
* @param days The number of days to add. To subtract days, use a negative value.
* @return The date with the given days added
*/
public static Date addDays(long dt, int days)
{
Calendar c = getCalendar();
if(dt > 0L)
c.setTimeInMillis(dt);
c.add(Calendar.DATE, days);
return c.getTime();
}
/**
* Returns the system date adding the given number of days.
* @param days The number of days to add. To subtract days, use a negative value.
* @return The date with the given days added
*/
public static Date addDays(int days)
{
return addDays(0L, days);
}
/**
* Returns the given date converted to UTC using the given timezone.
* @param millis The date to convert
* @param tz The timezone associated with the date
* @return The given date converted using the given timezone
*/
public static long convertToUtc(long millis, String tz)
{
long ret = millis;
if(tz != null && tz.length() > 0)
{
DateTime dt = new DateTime(millis, DateTimeZone.forID(tz));
ret = dt.withZoneRetainFields(DateTimeZone.forID("UTC")).getMillis();
}
return ret;
}
/**
* Returns the given date converted from UTC using the given timezone.
* @param millis The date to convert
* @param tz The timezone associated with the date
* @return The given date converted using the given timezone
*/
public static long convertFromUtc(long millis, String tz)
{
long ret = millis;
if(tz != null && tz.length() > 0)
{
DateTime dt = new DateTime(millis, DateTimeZone.forID("UTC"));
ret = dt.withZoneRetainFields(DateTimeZone.forID(tz)).getMillis();
}
return ret;
}
}