//*********************************************************************************
// class tig.Time
// Software released under the General Public License (version 2 or later), available at
// http://www.gnu.org/copyleft/gpl.html
//*********************************************************************************
package tig;
import tig.GeneralConstants;
import tig.DateFormatException;
import tig.HourFormatException;
import tig.Formats;
/**********************************************************************************
Class containing utility static methods for date manipulation.
<BR>The manipulation of dates is based on the use of 'julian days'.
<BR>The internationalization of this class is hard coded. The reason is that <CODE>parseDate</CODE>
and <CODE>formatHourDate</CODE> methods are locale dependant and must be modified if new languages are added.
<BR>Internationalized error messages have been hard coded to keep this class independant
from properties files.
@author Thierry Graff
@history oct 04 2001 : creation from jephem.astro.spaceTime.Time.java.
@history oct 15 2001 : added jdToDate and formatHourDate.
@history feb 04 2002 : Separated date and hour parsing and formating.
@todo : WARNING : coherence of exceptions thrown by the different methods
**********************************************************************************/
public abstract class Time implements GeneralConstants{
//=================================================================================
// PRIVATE CONSTANTS
//=================================================================================
// codes used for languages
private final static String EN = "en";
private final static String FR = "fr";
// Error message about lang
private final static String ERROR_LANG = "Parameter 'lang' must be \"en\" or \"fr\"";
//**************************** isLeapYear *************************************
/**
Tests if <CODE>y</CODE> corresponds to a leap year.
@param y positive number representing the year to test.
@return true if <CODE>y</CODE> is positive and corresponds to a leap year.
*/
public static boolean isLeapYear(int y){
if (y < 0) return false;
if ((y % 4 == 0 && !(y % 100 == 0)) || (y % 400 == 0))
return true;
else
return false;
}// end isLeapYear
//*************************** format methods from an int[] ***************************
/** Formats a date and an hour into a displayable String.
@param hourDate An array containing integers representing : year, month, day, hour, minut, second.
@param lang language code, as specified by ISO-639 norm (supported languages : "en" and "fr").
@return if lang='fr', format is "JJ/MM/AAAA HH:MM:SS" ;
<BR>if lang='en', format is "MM/JJ/AAAA HH:MM:SS".</LI>
@throws IllegalArgumentException if :
<LI>the length of 'hourDate' is different from 6 ;</LI>
<LI>the language is different from "en" or "fr".</LI>
*/
public static String formatHourDate(int[] hourDate, String lang){
// parameters checking
if(hourDate.length != 6)
throw new IllegalArgumentException("Parameter 'hourDate' must contain 6 integers");
if(!(lang.equals(EN) || lang.equals(FR)))
throw new IllegalArgumentException(ERROR_LANG);
String strDate = formatDate(new int[]{hourDate[0], hourDate[1], hourDate[2]}, lang);
String strHour = formatHour(new int[]{hourDate[3], hourDate[4], hourDate[5]}, lang);
return strDate + " " + strHour;
}// end formatHourDate(int[] hourDate, String lang)
/** Formats a date into a displayable String.
@param date An array containing 3 integers representing : year, month, day.
@param lang language code, as specified by ISO-639 norm (supported languages : "en" and "fr").
@return if lang='fr', format is "JJ/MM/AAAA" ;
<BR>if lang='en', format is "MM/JJ/AAAA".</LI>
@throws IllegalArgumentException if :
<LI>the length of 'date' is different from 3 ;</LI>
<LI>the language is different from "en" or "fr".</LI>
*/
public static String formatDate(int[] date, String lang){
// parameters checking
if(date.length != 3)
throw new IllegalArgumentException("Parameter 'date' must contain 3 integers");
if(!(lang.equals(EN) || lang.equals(FR)))
throw new IllegalArgumentException(ERROR_LANG);
String[] strDate = new String[3];
strDate[0] = String.valueOf(date[0]);
for (int i = 1; i < 3; i++)
strDate[i] = Formats.addZero(date[i]);
if (lang.equals(EN)){
return strDate[1] + "/" + strDate[2] + "/" + strDate[0];
}
else{ //if (lang.equals(FR)){
return strDate[2] + "/" + strDate[1] + "/" + strDate[0];
}
}// end formatDate(int[] date, String lang)
/** Formats an hour into a displayable String.
@param hour An array containing 3 integers representing : hour, minut, second.
@return A String formatted "HH:MM:SS", for lang='fr' or 'en';
@throws IllegalArgumentException if :
<LI>the length of 'hour' is different from 3 ;</LI>
<LI>the language is different from "en" or "fr".</LI>
*/
public static String formatHour(int[] hour, String lang){
// parameters checking
if(hour.length != 3)
throw new IllegalArgumentException("Parameter 'hour' must contain 3 integers");
if(!(lang.equals(EN) || lang.equals(FR)))
throw new IllegalArgumentException(ERROR_LANG);
String[] strHour = new String[3];
for (int i = 0; i < 3; i++)
strHour[i] = Formats.addZero(hour[i]);
return strHour[0] + ":" + strHour[1] + ":" + strHour[2];
}// end formatHour(int[] hour, String lang)
//*************************** format methods from a String ***************************
/** Formats a date the same way {@link #formatHourDate(int[], String)} does.
@throws DateFormatException if parameter 'strDate' is not correct.
@throws HourFormatException if parameter 'strHour' is not correct.
*/
public static String formatHourDate(String strDate, String strHour, String lang)
throws DateFormatException, HourFormatException{
try{
int[] hourDate = parseHourDate(strDate, strHour, lang);
return formatHourDate(hourDate, lang);
}
catch(HourFormatException e){ throw e;}
catch(DateFormatException e){ throw e;}
}// end formatHourDate(String strHourDate, String lang)
/** Formats a date the same way {@link #formatDate(int[], String)} does.
@throws DateFormatException if parameter 'strDate' is not correct.
*/
public static String formatDate(String strDate, String lang)
throws DateFormatException{
try{
int[] date = parseDate(strDate, lang);
return formatDate(date, lang);
}
catch(DateFormatException e){ throw e;}
}// end formatDate
/** Formats a date the same way {@link #formatHour(int[], String)} does.
@throws HourFormatException if parameter 'strHour' is not correct.
*/
public static String formatHour(String strHour, String lang)
throws HourFormatException{
try{
int[] hour = parseHour(strHour, lang);
return formatHour(hour, lang);
}
catch(HourFormatException e){ throw e;}
}// end formatHour
//************************************** parse methods **************************************
/** Transforms a date and an hour representated as Strings to an array of integers containing
(in this order : years, months, days, hours, minutes, seconds.
<BR>This method just calls {@link #parseHour(String, String)} and {@link #parseDate(String, String)}.
See their documentation for informations about parameter formats and exception thrown.
*/
public static int[] parseHourDate(String strDate, String strHour, String lang)
throws DateFormatException, HourFormatException, IllegalArgumentException{
// check language
if (!lang.equals(EN) && !lang.equals(FR))
throw new IllegalArgumentException("Parameter 'lang' must be 'en' or 'fr'");
try{
int[] date = parseDate(strDate, lang);
int[] hour = parseHour(strHour, lang);
return new int[]{date[0], date[1], date[2], hour[0], hour[1], hour[2]};
}
catch(DateFormatException e){throw e;}
catch(HourFormatException e){throw e;}
catch(IllegalArgumentException e){throw e;}
}// end parseHourDate
/** Transforms a date representated as a String to an array of integers containing the year,
month, day.
<BR><B>How to express the date in 'strDate'</B> :
<LI>Years, months and days must be separated by any non-numeric separator.</LI>
<LI>Years, months and days can be expressed with any number of digits ; years can be preceeded by a
minus sign (if you want to express a negative year, first put a separator, and then the '-').</LI>
<LI>For English ('lang' = "en"), the order in 'strDate' must be months, days, years.</LI>
<LI>For French ('lang' = "fr"), the order in 'strDate' must be days, months, years.</LI>
<BR><BR><B>Example of valid inputs and results</B>.
<BR>French :
<TABLE BORDER="1">
<TR><TH>strDate</TH><TH>years</TH><TH>months</TH><TH>days</TH></TR>
<TR><TD>18/07/1998</TD> <TD>18</TD> <TD>7</TD> <TD>1998</TD></TR>
<TR><TD>18.007:1998</TD> <TD>18</TD> <TD>7</TD> <TD>1998</TD></TR>
<TR><TD>9-10 2000</TD> <TD>9</TD> <TD>10</TD> <TD>2000</TD></TR>
<TR><TD>9 10 1</TD> <TD>9</TD> <TD>10</TD> <TD>1</TD></TR>
<TR><TD>9 10 -16</TD> <TD>9</TD> <TD>10</TD> <TD>-16</TD></TR>
<TR><TD>9-10--16</TD> <TD>9</TD> <TD>10</TD> <TD>-16</TD></TR>
<TR><TD>9-10-16</TD> <TD>9</TD> <TD>10</TD> <TD>16</TD></TR>
</TABLE>
<BR>English :
<TABLE BORDER="1">
<TR><TH>strDate</TH><TH>year</TH><TH>Month</TH><TH>Day</TH></TR>
<TR><TD>07/18/1998</TD> <TD>18</TD> <TD>7</TD> <TD>1998</TD></TR>
<TR><TD>007:18.1998</TD> <TD>18</TD> <TD>7</TD> <TD>1998</TD></TR>
<TR><TD>9-10 2000</TD> <TD>10</TD> <TD>9</TD> <TD>2000</TD></TR>
<TR><TD>9 10 1</TD> <TD>9</TD> <TD>10</TD> <TD>1</TD></TR>
<TR><TD>9 10 -16</TD> <TD>10</TD> <TD>9</TD> <TD>-16</TD></TR>
<TR><TD>9-10--16</TD> <TD>10</TD> <TD>9</TD> <TD>-16</TD></TR>
<TR><TD>9-10-16</TD> <TD>10</TD> <TD>9</TD> <TD>16</TD></TR>
</TABLE>
@param strDate A String containing the date, as specified above.
@param lang language code, as specified by ISO-639 norm (supported languages : "en" and "fr").
@return an array of integers in which are stored (in this order) years, months, days.
@throws IllegalArgumentException if parameter 'lang' is different from 'en' or 'fr'.
@throws DateFormatException if parameter 'strDate' is not correctly formatted.
*/
public static int[] parseDate(String strDate, String lang)
throws DateFormatException, IllegalArgumentException{
// check language
if (!lang.equals(EN) && !lang.equals(FR))
throw new IllegalArgumentException("Parameter 'lang' must be 'en' or 'fr'");
try{
int[] results = new int[3];
int len,i;
String str1=BLANK, str2=BLANK, str3=BLANK, yearSep=BLANK;
strDate = strDate.trim();
// *** 1 - Date parsing
len = strDate.length();
i=0;
// str1
while(i 1 && yearSep.charAt(yearSep.length() - 1)=='-')
results[0] = -results[0];
//*** 2 - Check date validity.
checkDate(results[0], results[1], results[2]);
return results;
}
catch(DateFormatException e){throw e;}
}// end parseDate
/** Transforms an hour representated as a String to an array of integers containing
(in this order : hours, minutes, seconds.
<BR>Parameter 'lang' has no effect.
<BR><B>How to express the hour in 'strHour'</B> :
<LI>Hours, minuts and seconds must be separated by any non-numeric character</LI>
<LI>Any non-numeric digit at the beginning or at the end of 'strHour" are skipped</LI>
<LI>If 'strHour' is empty, hours, minuts, seconds will be considered as equal to 0.</LI>
<LI>Seconds or {minutes and seconds} can be omitted, they will be considered as equal to 0.</LI>
<BR><BR><B>Example of valid inputs and results</B>.
<TABLE BORDER="1">
<TR><TH>strHour</TH><TH>hours</TH><TH>minuts</TH><TH>seconds</TH></TR>
<TR><TD>(empty string)</TD> <TD>0</TD> <TD>0</TD> <TD>0</TD></TR>
<TR><TD>12</TD> <TD>12</TD> <TD>0</TD> <TD>0</TD></TR>
<TR><TD>12h30m</TD> <TD>12</TD> <TD>30</TD> <TD>0</TD></TR>
<TR><TD>-12:30:40s</TD> <TD>12</TD> <TD>30</TD> <TD>40</TD></TR>
<TR><TD>000012h000030m00040</TD> <TD>12</TD> <TD>30</TD> <TD>40</TD></TR>
</TABLE>
@param strHour A String containing the hour, as specified above..
@param lang language code, as specified by ISO-639 norm (supported languages : 'en' and 'fr').
@return an array of integers in which are stored (in this order) hours, minuts, seconds.
@throws HourFormatException if parameter 'strHour' is not correctly formatted.
@throws IllegalArgumentException if parameter 'lang' is different from 'en' or 'fr'.
*/
public static int[] parseHour(String strHour, String lang)
throws HourFormatException, IllegalArgumentException{
// check language
if (!lang.equals(EN) && !lang.equals(FR))
throw new IllegalArgumentException("Parameter 'lang' must be 'en' or 'fr'");
try{
int[] results = new int[3];
int len,i;
String str1, str2, str3;
strHour = strHour.trim();
//*** Hour parsing
len = strHour.length();
if (len == 0){ // hour not specified
results[0] = 0; results[1] = 0; results[2] = 0; // hours, minuts, seconds
return results;
}
str1=str2=str3=BLANK;
i=0;
// remove useless characters at the begining of String.
while(iex : 23.75 means 23rd, 18h00m00s.
*/
public static double calcDecDay(int d, int h, int m, int s){
return d + h/24.0 + m/1440.0 + s/86400.0;
}//end calcDecDay
//=================================================================================
// PRIVATE METHODS
//=================================================================================
//********************** checkHour ****************************
/** Check hour validity. */
private static void checkHour(int h, int m, int s) throws HourFormatException{
if (h < 0 || h > 23) throw new HourFormatException("Hours must be between 0 and 23");
if (m < 0 || m > 59) throw new HourFormatException("Minutes must be between 0 and 59");
if (s < 0 || s > 59) throw new HourFormatException("Seconds must be between 0 and 59");
}// end checkHour
//********************** checkDate ****************************
/** Check date validity. Parameters : year, month, day. */
private static void checkDate(int y, int m, int d) throws DateFormatException{
int[] dpm = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; // days per month
// month validity
if (m < 1 || m > 12) throw new DateFormatException("Months must be between 1 and 12");
// day validity
if (m == 2){ // february
if (isLeapYear(y)){
if (d > 29) throw new DateFormatException("Days < 29 in february of a leap year");
}
else{
if (d > 28) throw new DateFormatException("Days < 28 in february of a normal year");
}
}
else{ // other months
if (d > dpm[m-1]) throw new DateFormatException("Days of this can't be greater than "+ dpm[m-1]);
}
}// end checkDate
//=================================================================================
//=================================================================================
// TESTS
//=================================================================================
//=================================================================================
/*
// **************** For tests only ****************
public static void main(String[] args){
// no complete argument checking
if(args[0].equalsIgnoreCase("testParseDate"))
testParseDate(args[1], args[2]);
else if(args[0].equalsIgnoreCase("testParseHour"))
testParseHour(args[1], args[2]);
else if(args[0].equalsIgnoreCase("testParseHourDate"))
testParseHourDate(args[1], args[2], args[3]);
else if(args[0].equalsIgnoreCase("testFormatDate"))
testFormatDate(args[1], args[2]);
else if(args[0].equalsIgnoreCase("testFormatHour"))
testFormatHour(args[1], args[2]);
else if(args[0].equalsIgnoreCase("testFormatHourDate"))
testFormatHourDate(args[1], args[2], args[3]);
else
System.out.println("first argument must be 'testParseDate' or 'testParseDate'" +
" or 'testFormatDate' or 'testFormatHour' or 'testFormatHourDate'");
}// end main
// **************** For tests only ****************
private static void testParseDate(String strDate, String lang){
try{
String[] str = {"year", "month", "day"};
int[] res = parseDate(strDate, lang);
for(int i = 0; i < 3; i++)
System.out.println(str[i] + " = " + res[i]);
}
catch(Exception e){e.printStackTrace();}
}// end testParseDate
// **************** For tests only ****************
private static void testParseHour(String strHour, String lang){
try{
String[] str = {"h", "m", "s"};
int[] res = parseHour(strHour, lang);
for(int i = 0; i < 3; i++)
System.out.println(str[i] + " = " + res[i]);
}
catch(Exception e){e.printStackTrace();}
}// end testParseHour
// **************** For tests only ****************
private static void testParseHourDate(String strHour, String strDate, String lang){
try{
String[] str = {"year", "month", "day", "h", "m", "s"};
int[] res = parseHourDate(strHour, strDate, lang);
for(int i = 0; i < 6; i++)
System.out.println(str[i] + " = " + res[i]);
}
catch(Exception e){e.printStackTrace();}
}// end testParseHour
// **************** For tests only ****************
private static void testFormatDate(String strDate, String lang){
try{
System.out.println(formatDate(strDate, lang));
}
catch(Exception e){e.printStackTrace();}
}// end testFormatDate
// **************** For tests only ****************
private static void testFormatHour(String strHour, String lang){
try{
System.out.println(formatHour(strHour, lang));
}
catch(Exception e){e.printStackTrace();}
}// end testFormatDate
// **************** For tests only ****************
private static void testFormatHourDate(String strHour, String strDate, String lang){
try{
System.out.println(formatHourDate(strHour, strDate, lang));
}
catch(Exception e){e.printStackTrace();}
}// end testFormatHourDate
*/
}//end abstract class Strings