/**
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
* License for the specific language governing rights and limitations under
* the License.
*
* The Original Code is OpenELIS code.
*
* Copyright (C) CIRG, University of Washington, Seattle WA. All Rights Reserved.
*
*/
package us.mn.state.health.lims.common.util;
import org.apache.commons.validator.GenericValidator;
import us.mn.state.health.lims.common.exception.LIMSRuntimeException;
import us.mn.state.health.lims.common.log.LogEvent;
import us.mn.state.health.lims.common.util.ConfigurationProperties.Property;
import java.sql.Timestamp;
import java.text.ParseException;
import java.text.ParsePosition;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Pattern;
public class DateUtil {
private static final int EPIC = 1970;
private static final String AMBIGUOUS_DATE_REGEX;
public static final String AMBIGUOUS_DATE_CHAR;
public static final String AMBIGUOUS_DATE_SEGMENT;
private static final Pattern FOUR_DIGITS = Pattern.compile("\\d{4}");
private static final Pattern TWO_DIGITS = Pattern.compile("\\d{2}");
private static final Pattern DIGIT = Pattern.compile("\\d");
private static final Pattern VALID_DATE = Pattern.compile("\\d{2}/\\d{2}/\\d{4}");
private static final long DAY_IN_MILLSEC = 1000L * 60L * 60L * 24L;
private static final long WEEK_MS = DAY_IN_MILLSEC * 7L;
static {
AMBIGUOUS_DATE_CHAR = ConfigurationProperties.getInstance().getPropertyValue(Property.AmbiguousDateHolder);
AMBIGUOUS_DATE_REGEX = "(?i)" + AMBIGUOUS_DATE_CHAR + AMBIGUOUS_DATE_CHAR;
AMBIGUOUS_DATE_SEGMENT = AMBIGUOUS_DATE_CHAR + AMBIGUOUS_DATE_CHAR;
}
public static String formatDateTimeAsText(Date date) {
SimpleDateFormat format = new SimpleDateFormat(getDateTimeFormat());
return format.format(date);
}
public static String formatDateAsText(Date date) {
SimpleDateFormat format = new SimpleDateFormat(getDateFormat());
return format.format(date);
}
public static java.sql.Date convertStringDateToSqlDate(String date) {
String stringLocale = SystemConfiguration.getInstance().getDefaultLocale().toString();
return convertStringDateToSqlDate(date, stringLocale);
}
public static java.sql.Date convertStringDateToSqlDate(String date, String stringLocale) throws LIMSRuntimeException {
SimpleDateFormat format = new SimpleDateFormat(getDateFormat());
format.setLenient(false);
java.sql.Date returnDate = null;
if (!StringUtil.isNullorNill(date)) {
try {
returnDate = new java.sql.Date(format.parse(date).getTime());
} catch (ParseException e) {
LogEvent.logError("DateUtil", "convertStringDateToSqlDate()", e.toString());
throw new LIMSRuntimeException("Error parsing date", e);
}
}
return returnDate;
}
public static java.sql.Date convertStringDateTimeToSqlDate(String date) throws LIMSRuntimeException {
SimpleDateFormat format = new SimpleDateFormat(getDateTimeFormat());
java.sql.Date returnDate = null;
if (!StringUtil.isNullorNill(date)) {
try {
returnDate = new java.sql.Date(format.parse(date).getTime());
} catch (ParseException e) {
LogEvent.logError("DateUtil", "convertStringDateTimeToSqlDate()", e.toString());
throw new LIMSRuntimeException("Error parsing date", e);
}
}
return returnDate;
}
public static Timestamp convertStringDateToTruncatedTimestamp(String date) throws LIMSRuntimeException {
SimpleDateFormat format = new SimpleDateFormat(getDateFormat());
Timestamp returnTimestamp = null;
if (!StringUtil.isNullorNill(date)) {
try {
returnTimestamp = new Timestamp(format.parse(date).getTime());
} catch (ParseException e) {
LogEvent.logError("DateUtil", "convertStringDateToTruncatedTimestamp()", e.toString());
throw new LIMSRuntimeException("Error parsing date", e);
}
}
return returnTimestamp;
}
public static Timestamp convertStringDateToTimestamp(String date) throws LIMSRuntimeException {
SimpleDateFormat format = new SimpleDateFormat(getDateTimeFormat());
Timestamp returnTimestamp = null;
if (!StringUtil.isNullorNill(date)) {
try {
returnTimestamp = new Timestamp(format.parse(date).getTime());
} catch (ParseException e) {
LogEvent.logError("DateUtil", "convertStringDateToTimestamp()", e.toString());
throw new LIMSRuntimeException("Error parsing date", e);
}
}
return returnTimestamp;
}
public static Timestamp convertStringDateToTimestampWithPatternNoLocale(String date, String pattern) throws LIMSRuntimeException {
SimpleDateFormat format = new SimpleDateFormat(pattern);
Timestamp returnTimestamp = null;
if (!StringUtil.isNullorNill(date)) {
try {
returnTimestamp = new Timestamp(format.parse(date).getTime());
} catch (ParseException e) {
LogEvent.logError("DateUtil", "convertStringDateToTimestampWithPattern()\nPattern: " + pattern + "\nDate: " + date,
e.toString());
throw new LIMSRuntimeException("Error parsing date", e);
}
}
return returnTimestamp;
}
public static Timestamp convertStringDateToTimestampWithPattern(String date, String pattern) throws LIMSRuntimeException {
Locale locale = SystemConfiguration.getInstance().getDefaultLocale();
SimpleDateFormat format = new SimpleDateFormat(pattern, locale);
Timestamp returnTimestamp = null;
if (!StringUtil.isNullorNill(date)) {
try {
returnTimestamp = new Timestamp(format.parse(date).getTime());
} catch (ParseException e) {
LogEvent.logError("DateUtil", "convertStringDateToTimestampWithPattern()\nlocale: " + locale + "\nPattern: " + pattern
+ "\nDate: " + date, e.toString());
throw new LIMSRuntimeException("Error parsing date", e);
}
}
return returnTimestamp;
}
// TIMESTAMP
public static Timestamp convertStringTimeToTimestamp(Timestamp date, String time) throws LIMSRuntimeException {
if (!StringUtil.isNullorNill(time) && date != null) {
Calendar cal = Calendar.getInstance();
cal.setTime(date);
cal.set(Calendar.HOUR_OF_DAY, Integer.valueOf( time.substring( 0, 2 ) ) );
cal.set(Calendar.MINUTE, Integer.valueOf( time.substring( 3, 5 ) ) );
date = new Timestamp(cal.getTimeInMillis());
}
return date;
}
public static String convertSqlDateToStringDate(java.sql.Date date) throws LIMSRuntimeException {
SimpleDateFormat format = new SimpleDateFormat(getDateFormat());
String returnDate = null;
if (date != null) {
try {
returnDate = format.format(date);
} catch (Exception e) {
LogEvent.logError("DateUtil", "convertSqlDateToStringDate()", e.toString());
throw new LIMSRuntimeException("Error converting date", e);
}
}
return returnDate;
}
public static String convertTimestampToStringDate(Timestamp date) throws LIMSRuntimeException {
return convertTimestampToStringDate(date, false);
}
public static String convertTimestampToTwoYearStringDate(Timestamp date) throws LIMSRuntimeException {
return convertTimestampToStringDate(date, true);
}
private static String convertTimestampToStringDate( Timestamp date, boolean twoYearDate) throws LIMSRuntimeException {
if( date == null){
return "";
}
String pattern = getDateFormat();
if( twoYearDate){
pattern = pattern.replace( "yyyy", "yy" );
}
SimpleDateFormat format = new SimpleDateFormat(pattern);
String returnDate;
try {
returnDate = format.format(date);
} catch (Exception e) {
LogEvent.logError("DateUtil", "convertTimestampToStringDate()", e.toString());
throw new LIMSRuntimeException("Error converting date", e);
}
return returnDate;
}
public static String convertTimestampToStringTime(Timestamp date) throws LIMSRuntimeException {
String returnTime = null;
String hours;
String minutes;
if (date != null) {
try {
Calendar cal = Calendar.getInstance();
cal.setTime(date);
if (cal.get(Calendar.HOUR_OF_DAY) <= 9) {
hours = "0" + String.valueOf(cal.get(Calendar.HOUR_OF_DAY));
} else {
hours = String.valueOf(cal.get(Calendar.HOUR_OF_DAY));
}
if (cal.get(Calendar.MINUTE) <= 9) {
minutes = "0" + String.valueOf(cal.get(Calendar.MINUTE));
} else {
minutes = String.valueOf(cal.get(Calendar.MINUTE));
}
returnTime = hours + ":" + minutes;
} catch (Exception e) {
LogEvent.logError("DateUtil", "convertTimestampToStringTime()", e.toString());
throw new LIMSRuntimeException("Error converting date", e);
}
}
return returnTime;
}
// Decodes a time value in "hh:mm:ss" format and returns it as milliseconds
// since midnight.
public static synchronized int decodeTime(String s) throws Exception {
SimpleDateFormat f = new SimpleDateFormat("HH:mm:ss");
// System.out.println("Passed in this time " +s);
TimeZone utcTimeZone = TimeZone.getTimeZone("UTC");
f.setTimeZone(utcTimeZone);
f.setLenient(false);
ParsePosition p = new ParsePosition(0);
Date d = f.parse(s, p);
if (d == null || !StringUtil.isRestOfStringBlank(s, p.getIndex())) {
throw new Exception("Invalid time value (hh:mm:ss): \"" + s + "\".");
}
return (int) d.getTime();
}
public static Timestamp formatStringToTimestamp(String ts) {
StringBuffer tssb = new StringBuffer();
tssb.append(ts);
if (ts.length() < 23) {
for (int i = 23; ts.length() < i; i--) {
tssb.append("0");
}
}
ts = tssb.toString();
SimpleDateFormat format = new SimpleDateFormat(getDateTimeFormat());
Timestamp tsToReturn = null;
if (!GenericValidator.isBlankOrNull(ts)) {
try {
java.util.Date date = format.parse(ts);
tsToReturn = new Timestamp(date.getTime());
} catch (Exception e) {
// bugzilla 2154
LogEvent.logError("DateUtil", "formatStringToTimestamp()", e.toString());
throw new LIMSRuntimeException("Error converting date", e);
}
}
return tsToReturn;
}
public static String getTwoDigitYear() {
int year = new GregorianCalendar().get(Calendar.YEAR) - 2000;
return String.format("%02d", year);
}
public static Timestamp convertAmbiguousStringDateToTimestamp(String dateForDisplay) {
dateForDisplay = normalizeAmbiguousDate(dateForDisplay);
return dateForDisplay == null ? null : convertStringDateToTruncatedTimestamp(dateForDisplay);
}
public static boolean yearSpecified(String dateString) {
String[] dateParts = dateString.split("/");
return dateParts.length == 3 && FOUR_DIGITS.matcher(dateParts[2]).find();
}
public static String normalizeAmbiguousDate(String date) {
if( VALID_DATE.matcher(date).find()){
return date;
}
String replaceValue = ConfigurationProperties.getInstance().getPropertyValue(Property.AmbiguousDateValue);
//N.B. This is suppose to clean-up historical data in the database. We will do the best we can
if( date.length() != 10){
String[] dateParts = date.split("/");
if( dateParts.length != 3 || !FOUR_DIGITS.matcher(dateParts[2]).find()){
return null;
}
if( date.length() > 10){
return replaceValue + "/" + replaceValue + "/" + date.split("/")[2];
}
for(int i = 0; i < 2; i++) {
if (dateParts[i].length() == 1 && DIGIT.matcher(dateParts[i]).find()) {
dateParts[i] = "0" + dateParts[i];
}else if (dateParts[i].length() == 1 || !TWO_DIGITS.matcher(dateParts[i]).find()) {
//if there is a single 'x' or 'X' then replacing it with 01 is what we want
return replaceValue + "/" + replaceValue + "/" + date.split("/")[2];
}
}
//if we made it here we have corrected what we can
return dateParts[0] + "/" + dateParts[1] + "/" + dateParts[2];
}else {
date = StringUtil.replaceCharAtIndex(date, '/', 2);
date = StringUtil.replaceCharAtIndex(date, '/', 5);
if( !yearSpecified(date)){
return null;
}
date = date.replaceAll(AMBIGUOUS_DATE_REGEX, replaceValue);
if(VALID_DATE.matcher(date).find()) {
return date;
}else{
return replaceValue + "/" + replaceValue + "/" + date.split("/")[2];
}
}
}
public static java.sql.Date getNowAsSqlDate() {
return new java.sql.Date(new Date().getTime());
}
public static String getCurrentAgeForDate(Timestamp birthDate, Timestamp endDate) {
if (birthDate != null) {
long age = endDate.getTime() - birthDate.getTime();
Date ageDate = new Date(age);
Calendar calendar = new GregorianCalendar();
calendar.setTime(ageDate);
return String.valueOf(calendar.get(Calendar.YEAR) - EPIC);
}
return null;
}
public static int getDaysInPastForDate(Date date) {
long age = new Date().getTime() - date.getTime();
return (int) Math.floor(age / DAY_IN_MILLSEC);
}
public static String getCurrentDateAsText() {
return formatDateAsText(new Date());
}
public static String getCurrentDateAsText(String pattern) {
if (GenericValidator.isBlankOrNull(pattern)) {
return null;
}
SimpleDateFormat format = new SimpleDateFormat(pattern);
return format.format(new Date());
}
public static int getAgeInWeeks(Date startDate, Date endDate) {
long duration = endDate.getTime() - startDate.getTime();
return (int) Math.floor(duration / WEEK_MS);
}
public static int getAgeInDays(Date startDate, Date endDate) {
long duration = endDate.getTime() - startDate.getTime();
return (int) Math.floor(duration / DAY_IN_MILLSEC);
}
public static int getAgeInMonths(Date startDate, Date endDate) {
Calendar start = new GregorianCalendar();
start.setTime(startDate);
int startMOY = start.get(Calendar.MONTH);
int startYear = start.get(Calendar.YEAR);
Calendar end = new GregorianCalendar();
end.setTime(endDate);
int endMOY = end.get(Calendar.MONTH);
int endYear = end.get(Calendar.YEAR);
// months between Jan. of start year and Jan. of end year
int dMons = (endYear - startYear) * 12;
// correct to actual months.
dMons += endMOY - startMOY;
// if the start day of month is after end day of month we have one too
// months.
if (start.get(Calendar.DAY_OF_MONTH) > end.get(Calendar.DAY_OF_MONTH)) {
--dMons;
}
return dMons;
}
public static int getAgeInYears(Date startDate, Date endDate) {
Calendar start = new GregorianCalendar();
start.setTime(startDate);
Calendar end = new GregorianCalendar();
end.setTime(endDate);
int year = end.get(Calendar.YEAR) - start.get(Calendar.YEAR);
if (start.get(Calendar.MONTH) > end.get(Calendar.MONTH)
|| (start.get(Calendar.MONTH) == end.get(Calendar.MONTH) &&
start.get(Calendar.DAY_OF_MONTH) > end.get(Calendar.DAY_OF_MONTH))) {
--year;
}
return year;
}
public static Timestamp getTimestampAtMidnightForDaysAgo(int days) {
Calendar now = new GregorianCalendar();
now.add(Calendar.DAY_OF_YEAR, -days);
now.set(Calendar.HOUR_OF_DAY, 0);
now.set(Calendar.MINUTE, 0);
now.set(Calendar.SECOND, 0);
now.set(Calendar.MILLISECOND, 0);
return new Timestamp(now.getTimeInMillis());
}
public static Timestamp getTimestampForBeginingOfYear() {
Calendar now = new GregorianCalendar();
now.set(Calendar.MONTH, 0);
now.set(Calendar.DAY_OF_MONTH, 1);
now.set(Calendar.HOUR_OF_DAY, 0);
now.set(Calendar.MINUTE, 0);
now.set(Calendar.SECOND, 0);
now.set(Calendar.MILLISECOND, 0);
return new Timestamp(now.getTimeInMillis());
}
public static Timestamp getTimestampForBeginningOfMonth() {
Calendar now = new GregorianCalendar();
now.set(Calendar.DAY_OF_MONTH, 1);
now.set(Calendar.HOUR_OF_DAY, 0);
now.set(Calendar.MINUTE, 0);
now.set(Calendar.SECOND, 0);
now.set(Calendar.MILLISECOND, 0);
return new Timestamp(now.getTimeInMillis());
}
public static int getMonthForTimestamp(Timestamp date) {
Calendar calendar = new GregorianCalendar();
calendar.setTime(date);
return calendar.get(Calendar.MONTH);
}
public static int getCurrentMonth() {
return new GregorianCalendar().get(Calendar.MONTH);
}
public static Timestamp getTimestampForBeginningOfMonthAgo( int months ) {
Calendar now = new GregorianCalendar();
now.add(Calendar.MONTH, -months);
now.set(Calendar.DAY_OF_MONTH, 1);
now.set(Calendar.HOUR_OF_DAY, 0);
now.set(Calendar.MINUTE, 0);
now.set(Calendar.SECOND, 0);
now.set(Calendar.MILLISECOND, 0);
return new Timestamp(now.getTimeInMillis());
}
public static int getCurrentYear() {
return new GregorianCalendar().get(Calendar.YEAR);
}
public static int getCurrentHour() {
return new GregorianCalendar().get(Calendar.HOUR_OF_DAY);
}
public static int getCurrentMinute() {
return new GregorianCalendar().get(Calendar.MINUTE);
}
public static Timestamp getNowAsTimestamp() {
return new Timestamp(new Date().getTime());
}
public static String convertTimestampToStringDateAndConfiguredHourTime( Timestamp timestamp ) {
if( ConfigurationProperties.getInstance().isPropertyValueEqual( Property.CLOCK_24, "true" )){
return convertTimestampToStringDateAndTime( timestamp );
}else{
return convertTimestampToStringDateAnd12HourTime( timestamp );
}
}
public static String convertTimestampToStringDateAndTime(Timestamp timestamp) {
if( timestamp == null){
return null;
}
return new SimpleDateFormat( getDateTimeFormat()).format(timestamp);
}
public static String convertTimestampToStringDateAnd12HourTime(Timestamp timestamp) {
if( timestamp == null){
return null;
}
return new SimpleDateFormat( getDateTime12HourFormat()).format(timestamp);
}
public static String convertTimestampToStringConfiguredHourTime(Timestamp timestamp) {
if( ConfigurationProperties.getInstance().isPropertyValueEqual( Property.CLOCK_24, "true" )){
return convertTimestampToStringHourTime( timestamp );
}else{
return convertTimestampToString12HourTime( timestamp );
}
}
public static String convertTimestampToString12HourTime(Timestamp timestamp) {
if( timestamp == null){
return null;
}
return new SimpleDateFormat( "KK:mm a").format(timestamp);
}
public static String convertTimestampToStringHourTime(Timestamp timestamp) {
if( timestamp == null){
return null;
}
return new SimpleDateFormat( "HH:mm").format(timestamp);
}
public static java.sql.Date convertTimestampToSqlDate( Timestamp timestamp){
return new java.sql.Date(timestamp.getTime());
}
public static Timestamp convertSqlDateToTimestamp(java.sql.Date date) {
return new Timestamp( date.getTime());
}
public static Object nowTimeAsText() {
return convertTimestampToStringTime(getNowAsTimestamp());
}
public static Timestamp convertStringDateStringTimeToTimestamp(String date, String time) {
if (!GenericValidator.isBlankOrNull(date) && !GenericValidator.isBlankOrNull(time))
date = date + " " + time;
else if (!GenericValidator.isBlankOrNull(date) && GenericValidator.isBlankOrNull(time))
date = date + " 00:00";
else
return null;
return convertStringDateToTimestamp(date);
}
/**
* The purpose of this is to not overwrite an old value with a less specified new value
* If the new time is empty but the dates are the same then return the timestamp of the old date/time
* If the dates differ use the new date/time
* @param oldDate
* @param oldTime
* @param newDate
* @param newTime
* @return
*/
public static Timestamp convertStringDatePreserveStringTimeToTimestamp(String oldDate, String oldTime, String newDate, String newTime){
if(!GenericValidator.isBlankOrNull(newTime)){
return convertStringDateStringTimeToTimestamp(newDate, newTime);
}
if(newDate != null && newDate.equals(oldDate)){
return convertStringDateStringTimeToTimestamp(oldDate, oldTime);
}
return convertStringDateStringTimeToTimestamp(newDate, newTime);
}
public static java.sql.Date addDaysToSQLDate( java.sql.Date date, int days){
return new java.sql.Date( date.getTime() + (days*DAY_IN_MILLSEC));
}
public static String getDateUserPrompt(){
Locale locale = getDateFormatLocale();
String yearRepresentation = StringUtil.getMessageForKey( "date.format.display.year" );
String dayRepresentation = StringUtil.getMessageForKey( "date.format.display.day" );
return StringUtil.getMessageForKeyAndLocale( "sample.date.format", dayRepresentation, yearRepresentation, locale );
}
public static String getDateFormat(){
Locale locale = getDateFormatLocale();
return StringUtil.getMessageForKeyAndLocale( "date.format.formatKey", locale );
}
public static String getDateTimeFormat(){
Locale locale = getDateFormatLocale();
return StringUtil.getMessageForKeyAndLocale( "timestamp.format.formatKey", locale );
}
public static String getDateTime12HourFormat(){
Locale locale = getDateFormatLocale();
return StringUtil.getMessageForKeyAndLocale( "timestamp.format.formatKey.12", locale );
}
public static Locale getDateFormatLocale(){
return SystemConfiguration.getInstance().getLocaleByLocalString( ConfigurationProperties.getInstance().getPropertyValue( Property.DEFAULT_DATE_LOCALE ) );
}
}