Some day, while I was implementing a DAO layer, it was required to create an order which the dispatch date was the order date plus 7 days.
Some additional business rules like postponing due to weekend, holidays, etc. added additional complexity.
So, I decided to create a CalendarSvc (calendar service) class to handle the required issues concerning date and time.
The following class offers that and many other facilities to support many date/time operations.
For instance:
/**
* Obtains the dispatch date.
* @return date plus dispatch period.
*/
public static Date dispatchDate(Date date) {
CalendarSvc dispatchDate = new CalendarSvc(date.getTime() + (dispatchPeriod * CalendarSvc.DAYMSEC));
return dispatchDate.date();
}
where dispatchPeriod is a variable defined on your config.ini that holds the number of days which is supposed to be dispatched (in this case was: dispatchPeriod = 7)
There are other examples on the header comment.
You're gonna find some references to another classes, but they are self-explanatory and I suppose that their name is enough to suggest the simple extra implementation required.
CalendarSvc.java
------------------------------------------------------------------------------------------------------------------
package javaLib.time.calendar;import java.text.DateFormat;
import java.text.DateFormatSymbols;
import java.text.SimpleDateFormat;
import java.util.Locale;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.StringTokenizer;
import java.util.TimeZone;
import javaLib.services.StrSvc;
import javaLib.time.DateTime;
/**
* javaLib.time.calendar.Days2Calendar.java
* project: javaLib
*
* target: Calendar services using GregorianCalendar.
*
*
*
* notes:
*
* Example#1 - difference between:
*
* Date date = CalendarSvc.dmy("31/12/2012", "/").date();
*
*
* CalendarSvc before = new CalendarSvc();
* try {
* Thread.sleep(10);
* } catch (InterruptedException e) {
* e.printStackTrace();
* }
* CalendarSvc after = new CalendarSvc();
* System.out.println(before.diffMillisec(after.getDate()));
* // same as:
* System.out.println(after.getDate().getTimeInMillis() - before.getDate().getTimeInMillis());
*
* CalendarSvc before = new CalendarSvc();
* System.out.println(before.getDate());
* System.out.println(before.ymdDate());
* System.out.println(before.ymdTimeDate());
* System.out.println(before.getDate().getTimeInMillis());
*
* CalendarSvc after = new CalendarSvc(2012,12,31);
* System.out.println(after.getDate());
* System.out.println(after.ymdTimeDate());
* System.out.println(after.getDate().getTimeInMillis());
*
* Long diff = before.diffMillisec(after.getDate());
* System.out.println("difference in milliseconds = " + diff);
* System.out.println("difference in days = " + CalendarSvc.millisec2days(diff));
* System.out.println("difference in days = " + before.daysBetween(after.getDate()));
*
* System.out.println("\n--- 1");
* Date d1 = new Date();
* long t = d1.getTime() + 3600000;
* Date d2 = new Date();
* d2.setTime(t);
* System.out.println("d1 = " + d1);
* System.out.println("d1.getTime() = " + d1.getTime());
* System.out.println("d2 = " + d2);
* System.out.println("d2.getTime() = " + d2.getTime());
* System.out.println("t = " + t);
*
* CalendarSvc calendarSvc = CalendarSvc.dmy("12/08/2012", "/");
* System.out.println(calendarSvc.dmyDate());
*
*
* Example#2 - using Date():
*
* System.out.println("\n--- 2");
*
* Date d1 = new Date();
* CalendarSvc date1 = new CalendarSvc(d1.getTime());
* System.out.println(date1.getDate());
* System.out.println(date1.ymdTimeDate());
* System.out.println(date1.getDate().getTimeInMillis());
*
*
* Example#3 - adding days and difference between:
*
* System.out.println("\n--- 3");
*
* CalendarSvc date3 = new CalendarSvc();
* System.out.println("today = " + date3.ymdTimeDate());
* System.out.println(date3.dayOfWeek());
* System.out.println(date3.getDate().getTimeInMillis());
*
* int days = 7;
* date3.addDays(days);
*
* System.out.println("today + " + days + " = " + date3.ymdTimeDate());
* System.out.println(date3.ymdTimeDate());
* System.out.println(date3.dayOfWeek());
* System.out.println(date3.getDate().getTimeInMillis());
*
*
* @see prj:
* @author alsdias@yahoo.com.br
* @version v.1.0.0 - Dec 26, 2012
*/
public class CalendarSvc implements ICalendarSvc {
protected GregorianCalendar date = null;
protected int year = 0;
protected int month = 0;
protected int day = 0;
protected int hour = 0;
protected int minute = 0;
protected int second = 0;
protected long millisec = 0L;
protected Locale locale = null;
protected TimeZone timezone = null;
/** one day in milliseconds */
public static final long DAYMSEC = 86400000L; // 24L * 60L * 60L * 1000L;
private String dateDelimiter = "/";
private String timeDelimiter = ":";
protected DateFormatSymbols symbols;
protected String[] shortMonthList, monthList, weekdayList;
private void setDefaults() {
locale = Locale.getDefault();
timezone = TimeZone.getDefault();
date = new GregorianCalendar(timezone, locale);
}
/**
* Common initialization procedures.
*/
private void init() {
year = date.get(GregorianCalendar.YEAR);
month = date.get(GregorianCalendar.MONTH) + 1;
day = date.get(GregorianCalendar.DAY_OF_MONTH);
hour = date.get(GregorianCalendar.HOUR_OF_DAY);
minute = date.get(GregorianCalendar.MINUTE);
second = date.get(GregorianCalendar.SECOND);
millisec = date.get(GregorianCalendar.MILLISECOND);
symbols = ((SimpleDateFormat)DateFormat.getInstance()).getDateFormatSymbols();
monthList = symbols.getMonths();
shortMonthList = symbols.getShortMonths();
weekdayList = symbols.getWeekdays();
}
/**
* Constructor using default values for timezone and locale.
*/
public CalendarSvc() {
setDefaults();
init();
}
/**
* Constructor for specific locale.
* @param locale
*/
public CalendarSvc(Locale locale) {
this.locale = locale;
timezone = TimeZone.getDefault();
date = new GregorianCalendar(timezone, locale);
init();
}
/**
* Constructor using specific timezone and locale.
*/
public CalendarSvc(TimeZone timezone, Locale locale) {
locale = Locale.getDefault();
timezone = TimeZone.getDefault();
date = new GregorianCalendar(timezone, locale);
init();
}
/**
* Constructor for creating a specific date.
* @param year
* @param month_
* @param day day of month
*/
public CalendarSvc(int year, int month, int day) {
setDefaults();
date.set(GregorianCalendar.YEAR, year);
date.set(GregorianCalendar.MONTH, month - 1);
date.set(GregorianCalendar.DAY_OF_MONTH, day);
init();
}
/**
* Constructor for creating a specific date and time.
* @param year
* @param month
* @param day
* @param hour
* @param minute
* @param sec
*/
public CalendarSvc(int year, int month, int day, int hour, int minute, int sec) {
setDefaults();
date.set(GregorianCalendar.YEAR, year);
date.set(GregorianCalendar.MONTH, month-1);
date.set(GregorianCalendar.DAY_OF_MONTH, day);
date.set(GregorianCalendar.HOUR_OF_DAY, hour);
date.set(GregorianCalendar.MINUTE, minute);
date.set(GregorianCalendar.SECOND, sec);
init();
}
public CalendarSvc(long milliseconds) {
setDefaults();
Date time = new Date();
time.setTime(milliseconds);
date.setTime(time);
init();
}
/*-----------------------------------------------------------------------------------------------------------------------
***SERVICES
-----------------------------------------------------------------------------------------------------------------------*/
public String dayOfWeek() {
return date.getDisplayName(GregorianCalendar.DAY_OF_WEEK, GregorianCalendar.ALL_STYLES, locale);
}
/**
* Adds a number of days to the date.
* @param number
*/
public void addDays(int number) {
Date time = new Date();
time.setTime(time.getTime() + number * CalendarSvc.DAYMSEC);
CalendarSvc newcal = new CalendarSvc(time.getTime());
this.date = newcal.getDate();
init();
}
/**
* Obtains the days between the current date and another.
* @param other
* @return
*/
public long daysBetween(Calendar other) {
return CalendarSvc.millisec2days(other.getTimeInMillis() - this.date.getTimeInMillis());
}
/**
* Returns YEAR/MONTH/DAY if default delimiter is used.
* @return
*/
public String ymdDate() {
return year + dateDelimiter + month + dateDelimiter + day;
}
/**
* Obtains CalendarSvc from a YMD formal date string.
* Ex: ymd("2012/08/12", "/");
* @param sdate
* @param delimiter
* @return
*/
public static CalendarSvc ymd(String sdate, String delimiter) {
StringTokenizer stokens = new StringTokenizer(sdate, delimiter);
return new CalendarSvc(Integer.valueOf(stokens.nextToken()), Integer.valueOf(stokens.nextToken()), Integer.valueOf(stokens.nextToken()));
}
/**
* Obtains CalendarSvc from a DMY formal date string.
* Ex: ymd("12/08/2012", "/");
* @param sdate
* @param delimiter
* @return
*/
public static CalendarSvc dmy(String sdate, String delimiter) {
StringTokenizer stokens = new StringTokenizer(sdate, delimiter);
int year = Integer.valueOf(stokens.nextToken());
int month = Integer.valueOf(stokens.nextToken());
int day = Integer.valueOf(stokens.nextToken());
return new CalendarSvc(day, month, year);
}
/**
* Returns DAY/MONTH/YEAR if default delimiter is used.
* @return
*/
public String dmyDate() {
return day + dateDelimiter + month + dateDelimiter + year;
}
/**
* Returns YEAR/MONTH/DAY HOUR:MINUTE:SECOND:MILLISECOND if default delimiters are used.
* @return
*/
public String ymdTimeDate() {
return year + dateDelimiter + month + dateDelimiter + day + " " + hour + timeDelimiter + minute + timeDelimiter + minute + timeDelimiter + millisec;
}
/**
* Returns the present instant as follow: YYYYMMDD_hh:mm:ss:SSS).
* Example: 080381_17:35:01:897
* @param language
* @param country
* @return timestamp format as follow: yyMMDD_H:mm:ss:SSS
*/
public static String timestamp(String language, String country) {
Date today = new Date();
Locale locale = new Locale(language, country);
SimpleDateFormat formatter = new SimpleDateFormat("yyMMDD_H:mm:ss:SSS", locale);
String output = formatter.format(today);
return output;
}
/**
* Returns the present instant as follow: YYYYMMDD_hh:mm:ss:SSS).
* Example: 080381_17:35:01:897
* @return timestamp format as follow: yyMMDD_H:mm:ss:SSS
*/
public String timestamp() {
SimpleDateFormat formatter = new SimpleDateFormat("yyMMDD_H:mm:ss:SSS", locale);
String output = formatter.format(date.getTime());
return output;
}
/**
* Returns the present instant according to format parameter.
* Example: 080381_17:35:01:897
* @param language
* @param country
* @param format Sun's SimpleDateFormat string pattern. For instance: yyMMDD_H:mm:ss:SSS
* @return timestamp formatted. If null or empty, assumes default = "yyMMDD_H:mm:ss:SSS"
*/
public static String timestamp(String language, String country, String format) {
if(format == null || format.isEmpty()) format = "yyMMDD_H:mm:ss:SSS";
Date today = new Date();
Locale locale = new Locale(language, country);
SimpleDateFormat formatter = new SimpleDateFormat(format, locale);
String output = formatter.format(today);
return output;
}
/**
* Returns the present instant according to format parameter.
* Example: 080381_17:35:01:897
* @param format Sun's SimpleDateFormat string pattern. For instance: yyMMDD_H:mm:ss:SSS
* @return timestamp formatted. If null or empty, assumes default = "yyMMDD_H:mm:ss:SSS"
*/
public String timestamp(String format) {
if(format == null || format.isEmpty()) format = "yyMMDD_H:mm:ss:SSS";
SimpleDateFormat formatter = new SimpleDateFormat(format, locale);
String output = formatter.format(date.getTime());
return output;
}
/**
* Returns a timestamp string without the milliseconds, formatted as follow if delimiter = "_":<br>
* YYYYMMDD_hhmmss
* @param timestamp formatted as follow: YYYYMMDD_hhmmss_msec<br>
* If null or empty returns an empty string. If size < 17 or missing time returns exception.
* @param delimiter the string used to delimiter the date fields.<br>
* If null or empty, assumes default = "/".
* @return For instance, if delimiter = "_", returns YYYYMMDD_hhmmss .<br>
* @throws StrException
*/
public static String getTimestampMinusMsec(String timestamp, String delimiter) throws Exception {
String exceptionMsg = "[ERROR]: javaLib.time.TimeSvc.getTimestampMinusMsec";
if(timestamp == null || timestamp.isEmpty()) return "";
if(timestamp.length() < 17) throw new Exception(exceptionMsg + ": invalid timestamp format - length = " + timestamp.length());
if(delimiter == null || delimiter.isEmpty()) delimiter = "/";
ArrayList<String> fields = StrSvc.str2arrayList(timestamp, delimiter);
if(fields.size() < 2) throw new Exception(exceptionMsg + ": invalid timestamp format - fields size = " + fields.size());
return fields.get(0) + "_" + fields.get(1);
}
/**
* Returns a timestamp string without the milliseconds, formatted as follow if delimiter = "_":<br>
* YYYYMMDD_hhmmss
* @param timestamp formatted as follow: YYYYMMDD_hhmmss_msec<br>
* If null or empty returns an empty string. If size < 17 or missing time returns exception.
* @param delimiter the string used to delimiter the date fields.<br>
* If null or empty, assumes default = "/".
* @return For instance, if delimiter = "_", returns YYYYMMDD_hhmmss .<br>
* @throws StrException
*/
public String getTimestampMinusMsec(String timestamp) throws Exception {
String exceptionMsg = "[ERROR]: javaLib.time.TimeSvc.getTimestampMinusMsec";
if(timestamp == null || timestamp.isEmpty()) return "";
if(timestamp.length() < 17) throw new Exception(exceptionMsg + ": invalid timestamp format - length = " + timestamp.length());
ArrayList<String> fields = StrSvc.str2arrayList(timestamp, dateDelimiter);
if(fields.size() < 2) throw new Exception(exceptionMsg + ": invalid timestamp format - fields size = " + fields.size());
return fields.get(0) + "_" + fields.get(1);
}
/**
* Converts time in milliseconds since Epoch to timestamp.
* @param millisec time in milliseconds since Epoch.
* @return timestamp in the format: YYYYMMDD_hhmmss_msec <br>
* If null or empty argument, returns empty string.
* @throws StrException
*/
public static String millisecToTimestamp(String millisec) throws Exception {
if(millisec == null || millisec.isEmpty()) return "";
int timekey_ = 0;
try {
timekey_ = Integer.parseInt(millisec);
} catch (Exception e) {
throw new Exception("[exception]: br.gov.datasus.synopsis.millisecToTimestamp: invalid millisec value");
}
DateTime dt = new DateTime(null, timekey_);
return dt.timestamp();
}
/**
* Converts a timestamp into milliseconds since Epoch.
* @param timestamp in the format: YYYYMMDD_hhmmss_msec
* @return time in milliseconds since Epoch.
* @throws StrException
*/
public static long timestampToMillisec(String timestamp) throws Exception {
DateTime dt = new DateTime(timestamp);
return dt.get_timeInMillis();
}
/**
* Converts to milliseconds.
* @param dateParts array where array[0]=YYYY, array[1]=MM, array[2]=DD.
* @return milliseconds from the Epoch(01/01/1970).
* @throws StrException
*/
public Long milliseconds(int[] dateParts) throws Exception {
if(dateParts == null || dateParts.length < 3) throw new Exception("[ERROR]: invalid syntax: missing date or values");
Calendar cal = Calendar.getInstance(locale);
cal.set(dateParts[0], dateParts[1], dateParts[2]);
return cal.getTimeInMillis();
}
/**
* Converts to milliseconds a string of date using a format pattern.
* @param s_date
* @param pattern
* @return milliseconds from the Epoch(01/01/1970).
* @throws StrException
*/
public static Long milliseconds(String s_date, String pattern) throws Exception {
String errorMsg = "[ERROR]: invalid syntax: missing date or values";
if(StrSvc.isNullEmpty(s_date) || StrSvc.isNullEmpty(pattern))
throw new Exception(errorMsg);
try {
Date date = new SimpleDateFormat(pattern).parse(s_date);
return date.getTime();
} catch (ParseException e) {
throw new Exception(errorMsg + " due to: " + e.getMessage());
}
}
/**
* Converts milliseconds to a time string according to its patterns.
* @param milliseconds
* @param pattern
* @return time string
*/
public static String time(Long milliseconds, String pattern) {
SimpleDateFormat formato = new SimpleDateFormat(pattern);
return formato.format(new Date(milliseconds));
}
/**
* Conversion of milliseconds to days.
* @param millisec
* @return
*/
public static long millisec2days(Long millisec) {
return millisec / 86400000;
}
/**
* Calculates in milliseconds the residual time in the year (from supplied date to the end of the year).
* @param date the present date.
* @return residual time in milliseconds.
*/
public static long residualMillisecInYear(Calendar date) {
GregorianCalendar lastday = new GregorianCalendar(date.get(GregorianCalendar.YEAR), 12, 31);
return lastday.getTimeInMillis() - date.getTimeInMillis();
}
/**
* Calculates the time difference compared to another in milliseconds.
* @param now
* @param other
* @return difference in milliseconds.
*/
public long diffMillisec(Calendar other) {
return other.getTimeInMillis() - date.getTimeInMillis();
}
/**
* Calculates the time difference between two dates in milliseconds.
* @param now
* @param after
* @return difference in milliseconds.
*/
public static long diffMillisec(Calendar now, Calendar after) {
return after.getTimeInMillis() - now.getTimeInMillis();
}
/**
* Converts days to number of years, months and days.
*
* @param days
* @return
*/
public Integer[] days2calendar(int days) {
int max_year = date.getActualMaximum(GregorianCalendar.DAY_OF_YEAR);
int max_month = date.getActualMaximum(GregorianCalendar.DAY_OF_MONTH);
Integer[] ymd = {0,0,0};
ymd[0] = (days >= max_year) ? days/max_year : 0;
int m = days - (ymd[0] * max_year);
ymd[1] = (m >= max_month) ? m/max_month : 0;
ymd[2] = m - (ymd[1] * max_month);
return ymd;
}
/**
* Straight accessor for Date object.
* @return Date object.
*/
public Date date() {
return date.getTime();
}
/**
* Obtains the short month notation.<br>
* Jan = 1, Feb = 2, ... Dec = 12.
* @param index 1-12
* @return short month notation, otherwise empty.
*/
@Override
public String shortMonth(int index) {
if(index < 1 || index > 13) return "";
return shortMonthList[index];
}
/**
* Obtains the month full notation.<br>
* January = 1, February = 2, ... December = 12.
* @param index 1-12
* @return full month notation, otherwise empty.
*/
@Override
public String month(int index) {
if(index < 1 || index > 13) return "";
return monthList[index];
}
/*-----------------------------------------------------------------------------------------------------------------------
***GETTERS/SETTERS
-----------------------------------------------------------------------------------------------------------------------*/
public int getHour() {
return hour;
}
public GregorianCalendar getDate() {
return date;
}
public void setDate(GregorianCalendar date) {
this.date = date;
}
public int getYear() {
return year;
}
public void setYear(int year) {
this.year = year;
}
public int getMonth() {
return month;
}
public void setMonth(int month) {
this.month = month;
}
public int getDay() {
return day;
}
public void setDay(int day) {
this.day = day;
}
public void setHour(int hour) {
this.hour = hour;
}
public int getMinute() {
return minute;
}
public void setMinute(int minute) {
this.minute = minute;
}
public int getSecond() {
return second;
}
public void setSecond(int second) {
this.second = second;
}
public long getMillisec() {
return millisec;
}
public void setMillisec(long millisec) {
this.millisec = millisec;
}
public String getDateDelimiter() {
return dateDelimiter;
}
public void setDateDelimiter(String dateDelimiter) {
this.dateDelimiter = dateDelimiter;
}
public String getTimeDelimiter() {
return timeDelimiter;
}
public void setTimeDelimiter(String timeDelimiter) {
this.timeDelimiter = timeDelimiter;
}
/*-----------------------------------------------------------------------------------------------------------------------
***GETTERS/SETTERS
-----------------------------------------------------------------------------------------------------------------------*/
public DateFormatSymbols getSymbols() {
return symbols;
}
public void setSymbols(DateFormatSymbols symbols) {
this.symbols = symbols;
}
public String[] getMonthList() {
return monthList;
}
public void setMonthList(String[] monthList) {
this.monthList = monthList;
}
public String[] getWeekdayList() {
return weekdayList;
}
public void setWeekdayList(String[] weekdayList) {
this.weekdayList = weekdayList;
}
public String[] getShortMonthList() {
return shortMonthList;
}
public void setShortMonthList(String[] shortMonthList) {
this.shortMonthList = shortMonthList;
}
@Override
public Locale getLocale() {
return locale;
}
@Override
public void setLocale(Locale locale) {
this.locale = locale;
}
/**
* For testing purpose.
* @param args
*/
// public static void main(String[] args) {
//
// }
}