Removed Chinese Calendar classes
X-SVN-Rev: 834
This commit is contained in:
parent
9fbf06bfe8
commit
2035894fe7
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* $RCSfile: CalendarCalc.java,v $ $Revision: 1.1 $ $Date: 2000/02/10 06:25:48 $
|
||||
* $RCSfile: CalendarCalc.java,v $ $Revision: 1.2 $ $Date: 2000/02/25 23:57:09 $
|
||||
*
|
||||
* (C) Copyright IBM Corp. 1998 - All Rights Reserved
|
||||
*
|
||||
@ -530,7 +530,7 @@ class CalendarCalcFrame extends Frame
|
||||
new CalendarRec("Islamic (true)", makeIslamic(false)),
|
||||
new CalendarRec("Buddhist", new BuddhistCalendar()),
|
||||
new CalendarRec("Japanese", new JapaneseCalendar()),
|
||||
new CalendarRec("Chinese", new ChineseCalendar()),
|
||||
// new CalendarRec("Chinese", new ChineseCalendar()),
|
||||
};
|
||||
|
||||
static private final Calendar makeIslamic(boolean civil) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* $RCSfile: CalendarCalc.java,v $ $Revision: 1.1 $ $Date: 2000/02/10 06:25:48 $
|
||||
* $RCSfile: CalendarCalc.java,v $ $Revision: 1.2 $ $Date: 2000/02/25 23:57:09 $
|
||||
*
|
||||
* (C) Copyright IBM Corp. 1998 - All Rights Reserved
|
||||
*
|
||||
@ -530,7 +530,7 @@ class CalendarCalcFrame extends Frame
|
||||
new CalendarRec("Islamic (true)", makeIslamic(false)),
|
||||
new CalendarRec("Buddhist", new BuddhistCalendar()),
|
||||
new CalendarRec("Japanese", new JapaneseCalendar()),
|
||||
new CalendarRec("Chinese", new ChineseCalendar()),
|
||||
// new CalendarRec("Chinese", new ChineseCalendar()),
|
||||
};
|
||||
|
||||
static private final Calendar makeIslamic(boolean civil) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* $RCSfile: TestFmwk.java,v $ $Revision: 1.4 $ $Date: 2000/02/25 18:57:12 $
|
||||
* $RCSfile: TestFmwk.java,v $ $Revision: 1.5 $ $Date: 2000/02/25 23:57:10 $
|
||||
*
|
||||
* (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
|
||||
* (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
|
||||
@ -70,7 +70,7 @@ public class TestFmwk {
|
||||
// to add a new test by simply adding a function to an existing class
|
||||
//------------------------------------------------------------------------
|
||||
|
||||
protected TestFmwk() {
|
||||
protected TestFmwk() {
|
||||
// Create a hashtable containing all the test methods.
|
||||
testMethods = new Hashtable();
|
||||
Method[] methods = getClass().getDeclaredMethods();
|
||||
@ -81,54 +81,52 @@ public class TestFmwk {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setParent(TestFmwk parent) {
|
||||
params = parent.params;
|
||||
}
|
||||
|
||||
protected void run(String[] args) throws Exception
|
||||
{
|
||||
System.out.println(getClass().getName() + " {");
|
||||
indentLevel++;
|
||||
|
||||
// Set up the log and reference streams. We use PrintWriters in order to
|
||||
// take advantage of character conversion. The JavaEsc converter will
|
||||
// convert Unicode outside the ASCII range to Java's \\uxxxx notation.
|
||||
log = new PrintWriter(System.out,true);
|
||||
|
||||
public void run(String[] args) throws Exception {
|
||||
if (params == null) params = new TestParams();
|
||||
// Parse the test arguments. They can be either the flag
|
||||
// "-verbose" or names of test methods. Create a list of
|
||||
// tests to be run.
|
||||
Vector testsToRun = new Vector( args.length );
|
||||
for( int i=0; i<args.length; i++ ) {
|
||||
if( args[i].equals("-verbose") ) {
|
||||
verbose = true;
|
||||
testsToRun = new Vector(args.length);
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
if (args[i].equals("-verbose")) {
|
||||
params.verbose = true;
|
||||
}
|
||||
else if( args[i].equals("-prompt") ) {
|
||||
prompt = true;
|
||||
else if (args[i].equals("-prompt")) {
|
||||
params.prompt = true;
|
||||
} else if (args[i].equals("-nothrow")) {
|
||||
nothrow = true;
|
||||
params.nothrow = true;
|
||||
} else {
|
||||
Object m = testMethods.get( args[i] );
|
||||
if( m != null ) {
|
||||
testsToRun.addElement( m );
|
||||
}
|
||||
else {
|
||||
Object m = testMethods.get(args[i]);
|
||||
if (m != null) {
|
||||
testsToRun.addElement(m);
|
||||
} else {
|
||||
usage();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If no test method names were given explicitly, run them all.
|
||||
if( testsToRun.size() == 0 ) {
|
||||
Enumeration methodNames = testMethods.elements();
|
||||
while( methodNames.hasMoreElements() ) {
|
||||
testsToRun.addElement( methodNames.nextElement() );
|
||||
}
|
||||
}
|
||||
if (params == null) params = new TestParams();
|
||||
System.out.println(getClass().getName() + " {");
|
||||
params.indentLevel++;
|
||||
Enumeration methodsToRun;
|
||||
|
||||
if (testsToRun.size() < 1) {
|
||||
methodsToRun = testMethods.elements();
|
||||
} else {
|
||||
methodsToRun = testsToRun.elements();
|
||||
}
|
||||
|
||||
// Run the list of tests given in the test arguments
|
||||
for( int i=0; i<testsToRun.size(); i++ ) {
|
||||
int oldCount = errorCount;
|
||||
while (methodsToRun.hasMoreElements()) {
|
||||
int oldCount = params.errorCount;
|
||||
|
||||
Method testMethod = (Method)testsToRun.elementAt(i);
|
||||
Method testMethod = (Method)methodsToRun.nextElement();
|
||||
writeTestName(testMethod.getName());
|
||||
|
||||
try {
|
||||
@ -137,16 +135,16 @@ public class TestFmwk {
|
||||
catch( IllegalAccessException e ) {
|
||||
errln("Can't acces test method " + testMethod.getName());
|
||||
} catch( InvocationTargetException e ) {
|
||||
errln("Uncaught exception thrown in test method "
|
||||
errln("Uncaught exception \""+e+"\"thrown in test method "
|
||||
+ testMethod.getName());
|
||||
e.getTargetException().printStackTrace(this.log);
|
||||
e.getTargetException().printStackTrace(this.params.log);
|
||||
}
|
||||
writeTestResult(errorCount - oldCount);
|
||||
writeTestResult(params.errorCount - oldCount);
|
||||
}
|
||||
indentLevel--;
|
||||
writeTestResult(errorCount);
|
||||
params.indentLevel--;
|
||||
writeTestResult(params.errorCount);
|
||||
|
||||
if (prompt) {
|
||||
if (params.prompt) {
|
||||
System.out.println("Hit RETURN to exit...");
|
||||
try {
|
||||
System.in.read();
|
||||
@ -154,8 +152,8 @@ public class TestFmwk {
|
||||
System.out.println("Exception: " + e.toString() + e.getMessage());
|
||||
}
|
||||
}
|
||||
if (nothrow) {
|
||||
System.exit(errorCount);
|
||||
if (params.nothrow) {
|
||||
System.exit(params.errorCount);
|
||||
}
|
||||
}
|
||||
|
||||
@ -163,10 +161,10 @@ public class TestFmwk {
|
||||
* Adds given string to the log if we are in verbose mode.
|
||||
*/
|
||||
protected void log( String message ) {
|
||||
if( verbose ) {
|
||||
indent(indentLevel + 1);
|
||||
log.print( message );
|
||||
log.flush();
|
||||
if( params.verbose ) {
|
||||
indent(params.indentLevel + 1);
|
||||
params.log.print( message );
|
||||
params.log.flush();
|
||||
}
|
||||
}
|
||||
|
||||
@ -178,12 +176,12 @@ public class TestFmwk {
|
||||
* Report an error
|
||||
*/
|
||||
protected void err( String message ) {
|
||||
errorCount++;
|
||||
indent(indentLevel + 1);
|
||||
log.print( message );
|
||||
log.flush();
|
||||
params.errorCount++;
|
||||
indent(params.indentLevel + 1);
|
||||
params.log.print( message );
|
||||
params.log.flush();
|
||||
|
||||
if (!nothrow) {
|
||||
if (!params.nothrow) {
|
||||
throw new RuntimeException(message);
|
||||
}
|
||||
}
|
||||
@ -192,38 +190,37 @@ public class TestFmwk {
|
||||
err(message + System.getProperty("line.separator"));
|
||||
}
|
||||
|
||||
|
||||
protected int getErrorCount() {
|
||||
return errorCount;
|
||||
return params.errorCount;
|
||||
}
|
||||
|
||||
protected void writeTestName(String testName) {
|
||||
indent(indentLevel);
|
||||
log.print(testName);
|
||||
log.flush();
|
||||
needLineFeed = true;
|
||||
indent(params.indentLevel);
|
||||
params.log.print(testName);
|
||||
params.log.flush();
|
||||
params.needLineFeed = true;
|
||||
}
|
||||
|
||||
protected void writeTestResult(int count) {
|
||||
if (!needLineFeed) {
|
||||
indent(indentLevel);
|
||||
log.print("}");
|
||||
if (!params.needLineFeed) {
|
||||
indent(params.indentLevel);
|
||||
params.log.print("}");
|
||||
}
|
||||
needLineFeed = false;
|
||||
params.needLineFeed = false;
|
||||
|
||||
if (count != 0) {
|
||||
log.println(" FAILED");
|
||||
params.log.println(" FAILED");
|
||||
} else {
|
||||
log.println(" Passed");
|
||||
params.log.println(" Passed");
|
||||
}
|
||||
}
|
||||
|
||||
private final void indent(int distance) {
|
||||
if (needLineFeed) {
|
||||
log.println(" {");
|
||||
needLineFeed = false;
|
||||
if (params.needLineFeed) {
|
||||
params.log.println(" {");
|
||||
params.needLineFeed = false;
|
||||
}
|
||||
log.print(spaces.substring(0, distance * 2));
|
||||
params.log.print(spaces.substring(0, distance * 2));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -262,16 +259,20 @@ public class TestFmwk {
|
||||
return hex(s.toString());
|
||||
}
|
||||
|
||||
protected boolean prompt = false;
|
||||
protected boolean nothrow = false;
|
||||
protected boolean verbose = false;
|
||||
private static class TestParams {
|
||||
public boolean prompt = false;
|
||||
public boolean nothrow = false;
|
||||
public boolean verbose = false;
|
||||
|
||||
private PrintWriter log;
|
||||
private int indentLevel = 0;
|
||||
private boolean needLineFeed = false;
|
||||
private int errorCount = 0;
|
||||
public PrintWriter log = new PrintWriter(System.out,true);
|
||||
public int indentLevel = 0;
|
||||
public boolean needLineFeed = false;
|
||||
public int errorCount = 0;
|
||||
}
|
||||
|
||||
private TestParams params = null;
|
||||
private Hashtable testMethods;
|
||||
private Vector testsToRun;
|
||||
private final String spaces = " ";
|
||||
}
|
||||
|
||||
|
@ -17,7 +17,7 @@ public class BigNumberFormatTest extends TestFmwk {
|
||||
public static void main(String[] args) throws Exception {
|
||||
new BigNumberFormatTest().run(args);
|
||||
}
|
||||
|
||||
|
||||
public void TestExponent() {
|
||||
DecimalFormatSymbols US = new DecimalFormatSymbols(Locale.US);
|
||||
DecimalFormat fmt1 = new DecimalFormat("0.###E0", US);
|
||||
|
@ -1,417 +0,0 @@
|
||||
/*
|
||||
* $RCSfile: ChineseCalendar.java,v $ $Revision: 1.1 $ $Date: 2000/02/10 06:25:55 $
|
||||
*/
|
||||
|
||||
|
||||
package com.ibm.util;
|
||||
|
||||
import com.ibm.text.ChineseDateFormat;
|
||||
|
||||
import java.text.DateFormat;
|
||||
import java.text.DateFormatSymbols;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.Locale;
|
||||
import java.util.ResourceBundle;
|
||||
import java.util.TimeZone;
|
||||
import java.util.Calendar;
|
||||
|
||||
// for debugging
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.SimpleTimeZone;
|
||||
|
||||
public class ChineseCalendar extends IBMCalendar {
|
||||
|
||||
// Need an Astronomer object for the moon age calculations
|
||||
private static CalendarAstronomer astro = new CalendarAstronomer();
|
||||
|
||||
// Useful millisecond constants
|
||||
private static final int SECOND_MS = 1000;
|
||||
private static final int MINUTE_MS = 60*SECOND_MS;
|
||||
private static final int HOUR_MS = 60*MINUTE_MS;
|
||||
private static final long DAY_MS = 24*HOUR_MS;
|
||||
private static final long WEEK_MS = 7*DAY_MS;
|
||||
private static final double MONTH_MS = (long)(astro.SYNODIC_MONTH * DAY_MS);
|
||||
private static final double YEAR_MS = (long)(astro.TROPICAL_YEAR * DAY_MS);
|
||||
static private final double PI = 3.14159265358979323846;
|
||||
static private final double DEG_RAD = PI / 180; // degrees -> radians
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// Public Constants
|
||||
//-------------------------------------------------------------------------
|
||||
public final static int LEAP_MONTH = Calendar.FIELD_COUNT;
|
||||
public final static int SOLAR_TERM = Calendar.FIELD_COUNT + 1;
|
||||
public final static int FIELD_COUNT = Calendar.FIELD_COUNT + 2;
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// Constructors
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Constructs a default <code>ChineseCalendar</code> using the current time
|
||||
* in the default time zone with the default locale.
|
||||
*/
|
||||
public ChineseCalendar() {
|
||||
this(TimeZone.getDefault(), Locale.getDefault());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a <code>ChineseCalendar</code> based on the current time
|
||||
* in the given time zone with the given locale.
|
||||
*
|
||||
* @param zone The time zone for the new calendar.
|
||||
*
|
||||
* @param aLocale The locale for the new calendar.
|
||||
*/
|
||||
public ChineseCalendar(TimeZone zone, Locale aLocale) {
|
||||
super(zone, aLocale);
|
||||
|
||||
fields = new int[FIELD_COUNT];
|
||||
isSet = new boolean[FIELD_COUNT];
|
||||
|
||||
setTimeInMillis(System.currentTimeMillis());
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// Functions for converting from field values to milliseconds and back...
|
||||
//
|
||||
// These are overrides of abstract methods on java.util.Calendar
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
private static long stdOffset(long utMillis)
|
||||
{
|
||||
return (utMillis > TZ_EPOCH) ? MODERN_OFFSET : BEIJING_OFFSET;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts UTC as milliseconds to time field values.
|
||||
* The time is <em>not</em>
|
||||
* recomputed first; to recompute the time, then the fields, call the
|
||||
* {@link #complete} method.
|
||||
*/
|
||||
protected void computeFields()
|
||||
{
|
||||
|
||||
// Figure out the current time in China as well, since months
|
||||
// are based on the day of the solstice and new moon in China
|
||||
long chinaOffset = stdOffset(time);
|
||||
long chinaMillis = time + chinaOffset;
|
||||
|
||||
// The basic rule governing the Chinese calendar is that the
|
||||
// Winter Solstice always falls in the 11th month of the year.
|
||||
|
||||
// Find the previous and next winter solstices, in GMT
|
||||
long solstice1 = getSolstice(time, false);
|
||||
long solstice2 = getSolstice(time, true);
|
||||
|
||||
debug("");
|
||||
debug("solstice1 = " + debug(solstice1));
|
||||
debug("solstice2 = " + debug(solstice2));
|
||||
|
||||
// Find the new moon after the previous solstice and before the next one
|
||||
long moon1 = newMoon(solstice1 + DAY_MS, true);
|
||||
long moon2 = newMoon(solstice2 + DAY_MS, false);
|
||||
|
||||
debug("moon1 = " + debug(moon1));
|
||||
debug("moon2 = " + debug(moon2));
|
||||
|
||||
// And the day when the current month started
|
||||
long monthStart = newMoon(time, false);
|
||||
|
||||
debug("monthStart= " + debug(monthStart));
|
||||
|
||||
fields[DATE] = (int)((time - monthStart) / DAY_MS) + 1;
|
||||
|
||||
// Is it a leap year?
|
||||
int months = (int)Math.round((moon2 - moon1) / MONTH_MS);
|
||||
|
||||
boolean leapYear = (months == 12);
|
||||
|
||||
debug("months=" + months + ", leapYear=" + leapYear);
|
||||
|
||||
int month = (int)Math.round((monthStart - moon1) / MONTH_MS);
|
||||
debug("month=" + month);
|
||||
fields[LEAP_MONTH] = 0;
|
||||
|
||||
if (leapYear) {
|
||||
// There's a leap month between these two solstices.
|
||||
// It's always the first month that does *not* contain the start
|
||||
// of a major term, i.e. a solar longitude that's an even
|
||||
// multiple of 30 degrees.
|
||||
long mStart = moon1;
|
||||
int tStart = getSolarTerm(mStart) / 2;
|
||||
|
||||
for (int m = 0; m < 13; m++) {
|
||||
long mEnd = newMoon(mStart + 29*DAY_MS, true); // End of this month
|
||||
int tEnd = getSolarTerm(mEnd) / 2;
|
||||
|
||||
debug("m=" + m + ", mStart=" + debug(mStart) + ", tStart=" + tStart + "\n"
|
||||
+ " mEnd= " + debug(mEnd) + ", tEnd=" + tEnd);
|
||||
|
||||
if (tEnd == tStart) {
|
||||
// A new major solar term did *not* start in this month
|
||||
debug("Month " + m + " is leap month");
|
||||
if (m == month) {
|
||||
fields[LEAP_MONTH] = 1;
|
||||
}
|
||||
if (m <= month) {
|
||||
month--;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
mStart = mEnd; // Start over with next month
|
||||
tStart = tEnd;
|
||||
}
|
||||
}
|
||||
debug("month=" + month);
|
||||
|
||||
// The winter solstice occurred in the 11th month of the last year....
|
||||
fields[MONTH] = (month + 11) % 12; // 0-based
|
||||
|
||||
debug("fields[MONTH]=" + fields[MONTH]);
|
||||
|
||||
int year = (int)Math.round((moon1 - EPOCH) / (TROPICAL_YEAR*DAY_MS))
|
||||
+ ((month > 0) ? 1 : 0);
|
||||
|
||||
fields[ERA] = (int)Math.floor((year-1) / 60) + 1;
|
||||
fields[YEAR] = (year-1) % 60 + 1;
|
||||
|
||||
|
||||
int dayOfWeek = (int)((time - EPOCH) / DAY_MS + MONDAY) % 7 + SUNDAY;
|
||||
if (dayOfWeek < 0) dayOfWeek += 7;
|
||||
|
||||
fields[DAY_OF_WEEK] = dayOfWeek;
|
||||
fields[WEEK_OF_MONTH] = weekNumber(fields[DATE], dayOfWeek);
|
||||
fields[DAY_OF_WEEK_IN_MONTH] = (fields[DATE]-1) / 7 + 1;
|
||||
|
||||
//
|
||||
// Compute the time zone offset and DST offset.
|
||||
// Since the TimeZone API expects the Gregorian year, month, etc.,
|
||||
// We have to convert to local Gregorian time in order to
|
||||
// figure out the time zone calculations. This is a bit slow, but
|
||||
// it saves us from doing some *really* nasty calculations here.
|
||||
//
|
||||
TimeZone zone = getTimeZone();
|
||||
int rawOffset = zone.getRawOffset();
|
||||
int dstOffset = 0; // Extra DST offset
|
||||
|
||||
if (zone.useDaylightTime()) {
|
||||
synchronized(gregorian) {
|
||||
gregorian.setTimeZone(zone);
|
||||
gregorian.setTime(new Date(time));
|
||||
dstOffset = gregorian.get(DST_OFFSET);
|
||||
}
|
||||
}
|
||||
long localMillis = time + rawOffset + dstOffset;
|
||||
|
||||
// Do the time-related fields....
|
||||
int millisInDay = (int)(localMillis % DAY_MS);
|
||||
|
||||
// Fill in all time-related fields based on millisInDay.
|
||||
fields[MILLISECOND] = millisInDay % 1000;
|
||||
millisInDay /= 1000;
|
||||
fields[SECOND] = millisInDay % 60;
|
||||
millisInDay /= 60;
|
||||
fields[MINUTE] = millisInDay % 60;
|
||||
millisInDay /= 60;
|
||||
fields[HOUR_OF_DAY] = millisInDay;
|
||||
fields[AM_PM] = millisInDay / 12;
|
||||
fields[HOUR] = millisInDay % 12;
|
||||
|
||||
fields[ZONE_OFFSET] = rawOffset;
|
||||
fields[DST_OFFSET] = dstOffset;
|
||||
|
||||
areFieldsSet = true;
|
||||
|
||||
// Careful here: We are manually setting the isSet[] flags to true, so we
|
||||
// must be sure that the above code actually does set all these fields.
|
||||
for (int i=0; i<FIELD_COUNT; ++i) isSet[i] = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts time field values to UTC as milliseconds.
|
||||
*
|
||||
* @exception IllegalArgumentException if a field has an invalid value
|
||||
* and {@link #isLenient isLenient} returns <code>false</code>.
|
||||
*/
|
||||
protected void computeTime() {
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// Min and Max methods....
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* The minimum and maximum values for all of the fields, for validation
|
||||
*/
|
||||
private static final int MinMax[][] = {
|
||||
// Min Greatest Min Least Max Max
|
||||
{ 0, 0, 0, 0 }, // ERA
|
||||
{ 0, 0, 59, 59 }, // YEAR
|
||||
{ 0, 0, 12, 12 }, // MONTH
|
||||
{ 0, 0, 51, 56 }, // WEEK_OF_YEAR
|
||||
{ 0, 0, 5, 6 }, // WEEK_OF_MONTH
|
||||
{ 1, 1, 29, 30 }, // DAY_OF_MONTH
|
||||
{ 1, 1, 365, 365 }, // DAY_OF_YEAR
|
||||
{ 1, 1, 7, 7 }, // DAY_OF_WEEK
|
||||
{ -1, -1, 4, 6 }, // DAY_OF_WEEK_IN_MONTH
|
||||
{ 0, 0, 1, 1 }, // AM_PM
|
||||
{ 0, 0, 11, 11 }, // HOUR
|
||||
{ 0, 0, 23, 23 }, // HOUR_OF_DAY
|
||||
{ 0, 0, 59, 59 }, // MINUTE
|
||||
{ 0, 0, 59, 59 }, // SECOND
|
||||
{ 0, 0, 999, 999 }, // MILLISECOND
|
||||
{ -12*HOUR_MS, -12*HOUR_MS, 12*HOUR_MS, 12*HOUR_MS }, // ZONE_OFFSET
|
||||
{ 0, 0, 1*HOUR_MS, 1*HOUR_MS }, // DST_OFFSET
|
||||
{ 0, 0, 1, 1 }, // LEAP_MONTH
|
||||
{ 1, 1, 12, 12 }, // MAJOR_TERM
|
||||
{ 1, 1, 12, 12 }, // MINOR_TERM
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the minimum value for the given field.
|
||||
* e.g. for DAY_OF_MONTH, 1
|
||||
*
|
||||
* @param field The field whose minimum value is desired.
|
||||
*
|
||||
* @see java.util.Calendar#getMinimum
|
||||
*/
|
||||
public int getMinimum(int field)
|
||||
{
|
||||
return MinMax[field][0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the highest minimum value for the given field. For the Hebrew
|
||||
* calendar, this always returns the same result as <code>getMinimum</code>.
|
||||
*
|
||||
* @param field The field whose greatest minimum value is desired.
|
||||
*
|
||||
* @see #getMinimum
|
||||
*/
|
||||
public int getGreatestMinimum(int field)
|
||||
{
|
||||
return MinMax[field][1];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the maximum value for the given field.
|
||||
* e.g. for {@link #DAY_OF_MONTH DAY_OF_MONTH}, 30
|
||||
*
|
||||
* @param field The field whose maximum value is desired.
|
||||
*
|
||||
* @see #getLeastMaximum
|
||||
* @see #getActualMaximum
|
||||
*/
|
||||
public int getMaximum(int field)
|
||||
{
|
||||
return MinMax[field][3];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the lowest maximum value for the given field. For most fields,
|
||||
* this returns the same result as {@link #getMaximum getMaximum}. However,
|
||||
* for some fields this can be a lower number. For example,
|
||||
* the maximum {@link #DAY_OF_MONTH DAY_OF_MONTH} in the Hebrew caleandar varies
|
||||
* from month to month, so this method returns 29 while <code>getMaximum</code>
|
||||
* returns 30.
|
||||
*
|
||||
* @param field The field whose least maximum value is desired.
|
||||
*
|
||||
* @see #getMaximum
|
||||
* @see #getActualMaximum
|
||||
*/
|
||||
public int getLeastMaximum(int field)
|
||||
{
|
||||
return MinMax[field][2];
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// Date format stuff
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
protected DateFormat getDateTimeFormat(int dateStyle, int timeStyle, Locale loc) {
|
||||
debug("in ChineseCalendar.getDateTimeFormat(dateStyle,timeStyle,loc)");
|
||||
|
||||
return new ChineseDateFormat(this, dateStyle, timeStyle, loc);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// Internal utilities
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// Astronomy
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
private static long getSolstice(long utAfter, boolean next) {
|
||||
long result = 0;
|
||||
synchronized (astro) {
|
||||
astro.setTime(utAfter);
|
||||
result = astro.getSunTime(CalendarAstronomer.WINTER_SOLSTICE, next);
|
||||
}
|
||||
long localMillis = result + stdOffset(result);
|
||||
return result - (localMillis % DAY_MS);
|
||||
}
|
||||
|
||||
private static long newMoon(long utAfter, boolean next) {
|
||||
long result = 0;
|
||||
synchronized (astro) {
|
||||
astro.setTime(utAfter);
|
||||
result = astro.getMoonTime(CalendarAstronomer.NEW_MOON, next);
|
||||
}
|
||||
long localMillis = result + stdOffset(result);
|
||||
return result - (localMillis % DAY_MS);
|
||||
}
|
||||
|
||||
private static int getSolarTerm(long uTime) {
|
||||
synchronized (astro) {
|
||||
astro.setTime(uTime);
|
||||
return (int)(2 + Math.floor(astro.getSunLongitude() / (15*DEG_RAD))) % 24;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// Internal Data
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
// Timezone stuff
|
||||
private static final long BEIJING_OFFSET = 7*HOUR_MS + 45*MINUTE_MS + 40*SECOND_MS;
|
||||
private static final long MODERN_OFFSET = 8*HOUR_MS;
|
||||
private static final long TZ_EPOCH = -1293822000000L; // 1/1/1929 AD
|
||||
|
||||
// Start of year 1 of the Chinese calendar
|
||||
private static final long EPOCH = -145349319600000L; // 2/15/2635 BC
|
||||
|
||||
private static final double SYNODIC_MONTH = CalendarAstronomer.SYNODIC_MONTH;
|
||||
private static final double TROPICAL_YEAR = CalendarAstronomer.TROPICAL_YEAR;
|
||||
|
||||
// Need a GregorianCalendar object for doing time zone calculations
|
||||
private static GregorianCalendar gregorian = new GregorianCalendar();
|
||||
|
||||
|
||||
private static CalendarCache cache = new CalendarCache();
|
||||
|
||||
static private void debug(String str) {
|
||||
if (true) {
|
||||
System.out.println(str);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static SimpleDateFormat gmtDf = new SimpleDateFormat("MM/dd/yyyy HH:mm");
|
||||
static SimpleDateFormat bstDf = new SimpleDateFormat("MM/dd/yyyy HH:mm");
|
||||
static {
|
||||
gmtDf.setTimeZone(new SimpleTimeZone(0, "GMT"));
|
||||
bstDf.setTimeZone(new SimpleTimeZone(8*HOUR_MS, "BST"));
|
||||
}
|
||||
|
||||
private static String debug(long t) {
|
||||
Date d = new Date(t);
|
||||
return bstDf.format(d) + " BST [" + gmtDf.format(d) + " GMT]";
|
||||
}
|
||||
};
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* $RCSfile: TestFmwk.java,v $ $Revision: 1.4 $ $Date: 2000/02/25 18:57:12 $
|
||||
* $RCSfile: TestFmwk.java,v $ $Revision: 1.5 $ $Date: 2000/02/25 23:57:10 $
|
||||
*
|
||||
* (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
|
||||
* (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
|
||||
@ -70,7 +70,7 @@ public class TestFmwk {
|
||||
// to add a new test by simply adding a function to an existing class
|
||||
//------------------------------------------------------------------------
|
||||
|
||||
protected TestFmwk() {
|
||||
protected TestFmwk() {
|
||||
// Create a hashtable containing all the test methods.
|
||||
testMethods = new Hashtable();
|
||||
Method[] methods = getClass().getDeclaredMethods();
|
||||
@ -81,54 +81,52 @@ public class TestFmwk {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setParent(TestFmwk parent) {
|
||||
params = parent.params;
|
||||
}
|
||||
|
||||
protected void run(String[] args) throws Exception
|
||||
{
|
||||
System.out.println(getClass().getName() + " {");
|
||||
indentLevel++;
|
||||
|
||||
// Set up the log and reference streams. We use PrintWriters in order to
|
||||
// take advantage of character conversion. The JavaEsc converter will
|
||||
// convert Unicode outside the ASCII range to Java's \\uxxxx notation.
|
||||
log = new PrintWriter(System.out,true);
|
||||
|
||||
public void run(String[] args) throws Exception {
|
||||
if (params == null) params = new TestParams();
|
||||
// Parse the test arguments. They can be either the flag
|
||||
// "-verbose" or names of test methods. Create a list of
|
||||
// tests to be run.
|
||||
Vector testsToRun = new Vector( args.length );
|
||||
for( int i=0; i<args.length; i++ ) {
|
||||
if( args[i].equals("-verbose") ) {
|
||||
verbose = true;
|
||||
testsToRun = new Vector(args.length);
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
if (args[i].equals("-verbose")) {
|
||||
params.verbose = true;
|
||||
}
|
||||
else if( args[i].equals("-prompt") ) {
|
||||
prompt = true;
|
||||
else if (args[i].equals("-prompt")) {
|
||||
params.prompt = true;
|
||||
} else if (args[i].equals("-nothrow")) {
|
||||
nothrow = true;
|
||||
params.nothrow = true;
|
||||
} else {
|
||||
Object m = testMethods.get( args[i] );
|
||||
if( m != null ) {
|
||||
testsToRun.addElement( m );
|
||||
}
|
||||
else {
|
||||
Object m = testMethods.get(args[i]);
|
||||
if (m != null) {
|
||||
testsToRun.addElement(m);
|
||||
} else {
|
||||
usage();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If no test method names were given explicitly, run them all.
|
||||
if( testsToRun.size() == 0 ) {
|
||||
Enumeration methodNames = testMethods.elements();
|
||||
while( methodNames.hasMoreElements() ) {
|
||||
testsToRun.addElement( methodNames.nextElement() );
|
||||
}
|
||||
}
|
||||
if (params == null) params = new TestParams();
|
||||
System.out.println(getClass().getName() + " {");
|
||||
params.indentLevel++;
|
||||
Enumeration methodsToRun;
|
||||
|
||||
if (testsToRun.size() < 1) {
|
||||
methodsToRun = testMethods.elements();
|
||||
} else {
|
||||
methodsToRun = testsToRun.elements();
|
||||
}
|
||||
|
||||
// Run the list of tests given in the test arguments
|
||||
for( int i=0; i<testsToRun.size(); i++ ) {
|
||||
int oldCount = errorCount;
|
||||
while (methodsToRun.hasMoreElements()) {
|
||||
int oldCount = params.errorCount;
|
||||
|
||||
Method testMethod = (Method)testsToRun.elementAt(i);
|
||||
Method testMethod = (Method)methodsToRun.nextElement();
|
||||
writeTestName(testMethod.getName());
|
||||
|
||||
try {
|
||||
@ -137,16 +135,16 @@ public class TestFmwk {
|
||||
catch( IllegalAccessException e ) {
|
||||
errln("Can't acces test method " + testMethod.getName());
|
||||
} catch( InvocationTargetException e ) {
|
||||
errln("Uncaught exception thrown in test method "
|
||||
errln("Uncaught exception \""+e+"\"thrown in test method "
|
||||
+ testMethod.getName());
|
||||
e.getTargetException().printStackTrace(this.log);
|
||||
e.getTargetException().printStackTrace(this.params.log);
|
||||
}
|
||||
writeTestResult(errorCount - oldCount);
|
||||
writeTestResult(params.errorCount - oldCount);
|
||||
}
|
||||
indentLevel--;
|
||||
writeTestResult(errorCount);
|
||||
params.indentLevel--;
|
||||
writeTestResult(params.errorCount);
|
||||
|
||||
if (prompt) {
|
||||
if (params.prompt) {
|
||||
System.out.println("Hit RETURN to exit...");
|
||||
try {
|
||||
System.in.read();
|
||||
@ -154,8 +152,8 @@ public class TestFmwk {
|
||||
System.out.println("Exception: " + e.toString() + e.getMessage());
|
||||
}
|
||||
}
|
||||
if (nothrow) {
|
||||
System.exit(errorCount);
|
||||
if (params.nothrow) {
|
||||
System.exit(params.errorCount);
|
||||
}
|
||||
}
|
||||
|
||||
@ -163,10 +161,10 @@ public class TestFmwk {
|
||||
* Adds given string to the log if we are in verbose mode.
|
||||
*/
|
||||
protected void log( String message ) {
|
||||
if( verbose ) {
|
||||
indent(indentLevel + 1);
|
||||
log.print( message );
|
||||
log.flush();
|
||||
if( params.verbose ) {
|
||||
indent(params.indentLevel + 1);
|
||||
params.log.print( message );
|
||||
params.log.flush();
|
||||
}
|
||||
}
|
||||
|
||||
@ -178,12 +176,12 @@ public class TestFmwk {
|
||||
* Report an error
|
||||
*/
|
||||
protected void err( String message ) {
|
||||
errorCount++;
|
||||
indent(indentLevel + 1);
|
||||
log.print( message );
|
||||
log.flush();
|
||||
params.errorCount++;
|
||||
indent(params.indentLevel + 1);
|
||||
params.log.print( message );
|
||||
params.log.flush();
|
||||
|
||||
if (!nothrow) {
|
||||
if (!params.nothrow) {
|
||||
throw new RuntimeException(message);
|
||||
}
|
||||
}
|
||||
@ -192,38 +190,37 @@ public class TestFmwk {
|
||||
err(message + System.getProperty("line.separator"));
|
||||
}
|
||||
|
||||
|
||||
protected int getErrorCount() {
|
||||
return errorCount;
|
||||
return params.errorCount;
|
||||
}
|
||||
|
||||
protected void writeTestName(String testName) {
|
||||
indent(indentLevel);
|
||||
log.print(testName);
|
||||
log.flush();
|
||||
needLineFeed = true;
|
||||
indent(params.indentLevel);
|
||||
params.log.print(testName);
|
||||
params.log.flush();
|
||||
params.needLineFeed = true;
|
||||
}
|
||||
|
||||
protected void writeTestResult(int count) {
|
||||
if (!needLineFeed) {
|
||||
indent(indentLevel);
|
||||
log.print("}");
|
||||
if (!params.needLineFeed) {
|
||||
indent(params.indentLevel);
|
||||
params.log.print("}");
|
||||
}
|
||||
needLineFeed = false;
|
||||
params.needLineFeed = false;
|
||||
|
||||
if (count != 0) {
|
||||
log.println(" FAILED");
|
||||
params.log.println(" FAILED");
|
||||
} else {
|
||||
log.println(" Passed");
|
||||
params.log.println(" Passed");
|
||||
}
|
||||
}
|
||||
|
||||
private final void indent(int distance) {
|
||||
if (needLineFeed) {
|
||||
log.println(" {");
|
||||
needLineFeed = false;
|
||||
if (params.needLineFeed) {
|
||||
params.log.println(" {");
|
||||
params.needLineFeed = false;
|
||||
}
|
||||
log.print(spaces.substring(0, distance * 2));
|
||||
params.log.print(spaces.substring(0, distance * 2));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -262,16 +259,20 @@ public class TestFmwk {
|
||||
return hex(s.toString());
|
||||
}
|
||||
|
||||
protected boolean prompt = false;
|
||||
protected boolean nothrow = false;
|
||||
protected boolean verbose = false;
|
||||
private static class TestParams {
|
||||
public boolean prompt = false;
|
||||
public boolean nothrow = false;
|
||||
public boolean verbose = false;
|
||||
|
||||
private PrintWriter log;
|
||||
private int indentLevel = 0;
|
||||
private boolean needLineFeed = false;
|
||||
private int errorCount = 0;
|
||||
public PrintWriter log = new PrintWriter(System.out,true);
|
||||
public int indentLevel = 0;
|
||||
public boolean needLineFeed = false;
|
||||
public int errorCount = 0;
|
||||
}
|
||||
|
||||
private TestParams params = null;
|
||||
private Hashtable testMethods;
|
||||
private Vector testsToRun;
|
||||
private final String spaces = " ";
|
||||
}
|
||||
|
||||
|
@ -17,7 +17,7 @@ public class BigNumberFormatTest extends TestFmwk {
|
||||
public static void main(String[] args) throws Exception {
|
||||
new BigNumberFormatTest().run(args);
|
||||
}
|
||||
|
||||
|
||||
public void TestExponent() {
|
||||
DecimalFormatSymbols US = new DecimalFormatSymbols(Locale.US);
|
||||
DecimalFormat fmt1 = new DecimalFormat("0.###E0", US);
|
||||
|
@ -15,63 +15,55 @@ public class TestAll extends TestFmwk {
|
||||
}
|
||||
|
||||
public void TestBigNumberFormat() throws Exception{
|
||||
com.ibm.test.bnf.BigNumberFormatTest.main(getArgs());
|
||||
run(new com.ibm.test.bnf.BigNumberFormatTest());
|
||||
}
|
||||
|
||||
public void TestCompression1() throws Exception{
|
||||
com.ibm.test.compression.Test.main(getArgs());
|
||||
run(new com.ibm.test.compression.DecompressionTest());
|
||||
}
|
||||
|
||||
public void TestCompression2() throws Exception{
|
||||
com.ibm.test.compression.Main.main(getArgs());
|
||||
run(new com.ibm.test.compression.ExhaustiveTest());
|
||||
}
|
||||
|
||||
public void TestNormalizer1() throws Exception{
|
||||
com.ibm.test.normalizer.BasicTest.main(getArgs());
|
||||
run(new com.ibm.test.normalizer.BasicTest());
|
||||
}
|
||||
|
||||
public void TestNormalizer2() throws Exception {
|
||||
com.ibm.test.normalizer.ExhaustiveTest.main(getArgs());
|
||||
run(new com.ibm.test.normalizer.ExhaustiveTest());
|
||||
}
|
||||
|
||||
public void TestNormalizer3() throws Exception {
|
||||
com.ibm.test.normalizer.FooTest.main(getArgs());
|
||||
run(new com.ibm.test.normalizer.FooTest());
|
||||
}
|
||||
|
||||
public void TestRuleBasedNumberFormat1() throws Exception {
|
||||
com.ibm.test.rbnf.RbnfTest.main(getArgs());
|
||||
run(new com.ibm.test.rbnf.RbnfTest());
|
||||
}
|
||||
|
||||
public void TestRulebasedNumberFormat2() throws Exception {
|
||||
com.ibm.test.rbnf.RbnfRoundTripTest.main(getArgs());
|
||||
run(new com.ibm.test.rbnf.RbnfRoundTripTest());
|
||||
}
|
||||
|
||||
public void TestRuleBasedBreakIteartor1() throws Exception {
|
||||
com.ibm.test.RuleBasedBreakIterator.SimpleBITest.main(getArgs());
|
||||
run(new com.ibm.test.RuleBasedBreakIterator.SimpleBITest());
|
||||
}
|
||||
|
||||
public void TestRuleBasedBreakIteartor2() throws Exception {
|
||||
com.ibm.test.RuleBasedBreakIterator.BreakIteratorTest.main(getArgs());
|
||||
run(new com.ibm.test.RuleBasedBreakIterator.BreakIteratorTest());
|
||||
}
|
||||
|
||||
public void TestTranslit1() throws Exception {
|
||||
com.ibm.test.translit.UnicodeSetTest.main(getArgs());
|
||||
run(new com.ibm.test.translit.UnicodeSetTest());
|
||||
}
|
||||
|
||||
public void TestTranslit2() throws Exception {
|
||||
com.ibm.test.translit.TransliteratorTest.main(getArgs());
|
||||
run(new com.ibm.test.translit.TransliteratorTest());
|
||||
}
|
||||
|
||||
private void run(TestFmwk test) {
|
||||
test.setParent(this);
|
||||
test.run(new String[0]);
|
||||
}
|
||||
|
||||
private String[] getArgs() {
|
||||
int size =
|
||||
((verbose) ? 1 : 0)
|
||||
+ ((prompt) ? 1 : 0)
|
||||
+ ((nothrow) ? 1 : 0);
|
||||
String [] result = new String[size];
|
||||
if (verbose) result[--size] = "-verbose";
|
||||
if (prompt) result[--size] = "-prompt";
|
||||
if (nothrow) result[--size] = "-nothrow";
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,417 +0,0 @@
|
||||
/*
|
||||
* $RCSfile: ChineseCalendar.java,v $ $Revision: 1.1 $ $Date: 2000/02/10 06:25:55 $
|
||||
*/
|
||||
|
||||
|
||||
package com.ibm.util;
|
||||
|
||||
import com.ibm.text.ChineseDateFormat;
|
||||
|
||||
import java.text.DateFormat;
|
||||
import java.text.DateFormatSymbols;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.Locale;
|
||||
import java.util.ResourceBundle;
|
||||
import java.util.TimeZone;
|
||||
import java.util.Calendar;
|
||||
|
||||
// for debugging
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.SimpleTimeZone;
|
||||
|
||||
public class ChineseCalendar extends IBMCalendar {
|
||||
|
||||
// Need an Astronomer object for the moon age calculations
|
||||
private static CalendarAstronomer astro = new CalendarAstronomer();
|
||||
|
||||
// Useful millisecond constants
|
||||
private static final int SECOND_MS = 1000;
|
||||
private static final int MINUTE_MS = 60*SECOND_MS;
|
||||
private static final int HOUR_MS = 60*MINUTE_MS;
|
||||
private static final long DAY_MS = 24*HOUR_MS;
|
||||
private static final long WEEK_MS = 7*DAY_MS;
|
||||
private static final double MONTH_MS = (long)(astro.SYNODIC_MONTH * DAY_MS);
|
||||
private static final double YEAR_MS = (long)(astro.TROPICAL_YEAR * DAY_MS);
|
||||
static private final double PI = 3.14159265358979323846;
|
||||
static private final double DEG_RAD = PI / 180; // degrees -> radians
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// Public Constants
|
||||
//-------------------------------------------------------------------------
|
||||
public final static int LEAP_MONTH = Calendar.FIELD_COUNT;
|
||||
public final static int SOLAR_TERM = Calendar.FIELD_COUNT + 1;
|
||||
public final static int FIELD_COUNT = Calendar.FIELD_COUNT + 2;
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// Constructors
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Constructs a default <code>ChineseCalendar</code> using the current time
|
||||
* in the default time zone with the default locale.
|
||||
*/
|
||||
public ChineseCalendar() {
|
||||
this(TimeZone.getDefault(), Locale.getDefault());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a <code>ChineseCalendar</code> based on the current time
|
||||
* in the given time zone with the given locale.
|
||||
*
|
||||
* @param zone The time zone for the new calendar.
|
||||
*
|
||||
* @param aLocale The locale for the new calendar.
|
||||
*/
|
||||
public ChineseCalendar(TimeZone zone, Locale aLocale) {
|
||||
super(zone, aLocale);
|
||||
|
||||
fields = new int[FIELD_COUNT];
|
||||
isSet = new boolean[FIELD_COUNT];
|
||||
|
||||
setTimeInMillis(System.currentTimeMillis());
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// Functions for converting from field values to milliseconds and back...
|
||||
//
|
||||
// These are overrides of abstract methods on java.util.Calendar
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
private static long stdOffset(long utMillis)
|
||||
{
|
||||
return (utMillis > TZ_EPOCH) ? MODERN_OFFSET : BEIJING_OFFSET;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts UTC as milliseconds to time field values.
|
||||
* The time is <em>not</em>
|
||||
* recomputed first; to recompute the time, then the fields, call the
|
||||
* {@link #complete} method.
|
||||
*/
|
||||
protected void computeFields()
|
||||
{
|
||||
|
||||
// Figure out the current time in China as well, since months
|
||||
// are based on the day of the solstice and new moon in China
|
||||
long chinaOffset = stdOffset(time);
|
||||
long chinaMillis = time + chinaOffset;
|
||||
|
||||
// The basic rule governing the Chinese calendar is that the
|
||||
// Winter Solstice always falls in the 11th month of the year.
|
||||
|
||||
// Find the previous and next winter solstices, in GMT
|
||||
long solstice1 = getSolstice(time, false);
|
||||
long solstice2 = getSolstice(time, true);
|
||||
|
||||
debug("");
|
||||
debug("solstice1 = " + debug(solstice1));
|
||||
debug("solstice2 = " + debug(solstice2));
|
||||
|
||||
// Find the new moon after the previous solstice and before the next one
|
||||
long moon1 = newMoon(solstice1 + DAY_MS, true);
|
||||
long moon2 = newMoon(solstice2 + DAY_MS, false);
|
||||
|
||||
debug("moon1 = " + debug(moon1));
|
||||
debug("moon2 = " + debug(moon2));
|
||||
|
||||
// And the day when the current month started
|
||||
long monthStart = newMoon(time, false);
|
||||
|
||||
debug("monthStart= " + debug(monthStart));
|
||||
|
||||
fields[DATE] = (int)((time - monthStart) / DAY_MS) + 1;
|
||||
|
||||
// Is it a leap year?
|
||||
int months = (int)Math.round((moon2 - moon1) / MONTH_MS);
|
||||
|
||||
boolean leapYear = (months == 12);
|
||||
|
||||
debug("months=" + months + ", leapYear=" + leapYear);
|
||||
|
||||
int month = (int)Math.round((monthStart - moon1) / MONTH_MS);
|
||||
debug("month=" + month);
|
||||
fields[LEAP_MONTH] = 0;
|
||||
|
||||
if (leapYear) {
|
||||
// There's a leap month between these two solstices.
|
||||
// It's always the first month that does *not* contain the start
|
||||
// of a major term, i.e. a solar longitude that's an even
|
||||
// multiple of 30 degrees.
|
||||
long mStart = moon1;
|
||||
int tStart = getSolarTerm(mStart) / 2;
|
||||
|
||||
for (int m = 0; m < 13; m++) {
|
||||
long mEnd = newMoon(mStart + 29*DAY_MS, true); // End of this month
|
||||
int tEnd = getSolarTerm(mEnd) / 2;
|
||||
|
||||
debug("m=" + m + ", mStart=" + debug(mStart) + ", tStart=" + tStart + "\n"
|
||||
+ " mEnd= " + debug(mEnd) + ", tEnd=" + tEnd);
|
||||
|
||||
if (tEnd == tStart) {
|
||||
// A new major solar term did *not* start in this month
|
||||
debug("Month " + m + " is leap month");
|
||||
if (m == month) {
|
||||
fields[LEAP_MONTH] = 1;
|
||||
}
|
||||
if (m <= month) {
|
||||
month--;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
mStart = mEnd; // Start over with next month
|
||||
tStart = tEnd;
|
||||
}
|
||||
}
|
||||
debug("month=" + month);
|
||||
|
||||
// The winter solstice occurred in the 11th month of the last year....
|
||||
fields[MONTH] = (month + 11) % 12; // 0-based
|
||||
|
||||
debug("fields[MONTH]=" + fields[MONTH]);
|
||||
|
||||
int year = (int)Math.round((moon1 - EPOCH) / (TROPICAL_YEAR*DAY_MS))
|
||||
+ ((month > 0) ? 1 : 0);
|
||||
|
||||
fields[ERA] = (int)Math.floor((year-1) / 60) + 1;
|
||||
fields[YEAR] = (year-1) % 60 + 1;
|
||||
|
||||
|
||||
int dayOfWeek = (int)((time - EPOCH) / DAY_MS + MONDAY) % 7 + SUNDAY;
|
||||
if (dayOfWeek < 0) dayOfWeek += 7;
|
||||
|
||||
fields[DAY_OF_WEEK] = dayOfWeek;
|
||||
fields[WEEK_OF_MONTH] = weekNumber(fields[DATE], dayOfWeek);
|
||||
fields[DAY_OF_WEEK_IN_MONTH] = (fields[DATE]-1) / 7 + 1;
|
||||
|
||||
//
|
||||
// Compute the time zone offset and DST offset.
|
||||
// Since the TimeZone API expects the Gregorian year, month, etc.,
|
||||
// We have to convert to local Gregorian time in order to
|
||||
// figure out the time zone calculations. This is a bit slow, but
|
||||
// it saves us from doing some *really* nasty calculations here.
|
||||
//
|
||||
TimeZone zone = getTimeZone();
|
||||
int rawOffset = zone.getRawOffset();
|
||||
int dstOffset = 0; // Extra DST offset
|
||||
|
||||
if (zone.useDaylightTime()) {
|
||||
synchronized(gregorian) {
|
||||
gregorian.setTimeZone(zone);
|
||||
gregorian.setTime(new Date(time));
|
||||
dstOffset = gregorian.get(DST_OFFSET);
|
||||
}
|
||||
}
|
||||
long localMillis = time + rawOffset + dstOffset;
|
||||
|
||||
// Do the time-related fields....
|
||||
int millisInDay = (int)(localMillis % DAY_MS);
|
||||
|
||||
// Fill in all time-related fields based on millisInDay.
|
||||
fields[MILLISECOND] = millisInDay % 1000;
|
||||
millisInDay /= 1000;
|
||||
fields[SECOND] = millisInDay % 60;
|
||||
millisInDay /= 60;
|
||||
fields[MINUTE] = millisInDay % 60;
|
||||
millisInDay /= 60;
|
||||
fields[HOUR_OF_DAY] = millisInDay;
|
||||
fields[AM_PM] = millisInDay / 12;
|
||||
fields[HOUR] = millisInDay % 12;
|
||||
|
||||
fields[ZONE_OFFSET] = rawOffset;
|
||||
fields[DST_OFFSET] = dstOffset;
|
||||
|
||||
areFieldsSet = true;
|
||||
|
||||
// Careful here: We are manually setting the isSet[] flags to true, so we
|
||||
// must be sure that the above code actually does set all these fields.
|
||||
for (int i=0; i<FIELD_COUNT; ++i) isSet[i] = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts time field values to UTC as milliseconds.
|
||||
*
|
||||
* @exception IllegalArgumentException if a field has an invalid value
|
||||
* and {@link #isLenient isLenient} returns <code>false</code>.
|
||||
*/
|
||||
protected void computeTime() {
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// Min and Max methods....
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* The minimum and maximum values for all of the fields, for validation
|
||||
*/
|
||||
private static final int MinMax[][] = {
|
||||
// Min Greatest Min Least Max Max
|
||||
{ 0, 0, 0, 0 }, // ERA
|
||||
{ 0, 0, 59, 59 }, // YEAR
|
||||
{ 0, 0, 12, 12 }, // MONTH
|
||||
{ 0, 0, 51, 56 }, // WEEK_OF_YEAR
|
||||
{ 0, 0, 5, 6 }, // WEEK_OF_MONTH
|
||||
{ 1, 1, 29, 30 }, // DAY_OF_MONTH
|
||||
{ 1, 1, 365, 365 }, // DAY_OF_YEAR
|
||||
{ 1, 1, 7, 7 }, // DAY_OF_WEEK
|
||||
{ -1, -1, 4, 6 }, // DAY_OF_WEEK_IN_MONTH
|
||||
{ 0, 0, 1, 1 }, // AM_PM
|
||||
{ 0, 0, 11, 11 }, // HOUR
|
||||
{ 0, 0, 23, 23 }, // HOUR_OF_DAY
|
||||
{ 0, 0, 59, 59 }, // MINUTE
|
||||
{ 0, 0, 59, 59 }, // SECOND
|
||||
{ 0, 0, 999, 999 }, // MILLISECOND
|
||||
{ -12*HOUR_MS, -12*HOUR_MS, 12*HOUR_MS, 12*HOUR_MS }, // ZONE_OFFSET
|
||||
{ 0, 0, 1*HOUR_MS, 1*HOUR_MS }, // DST_OFFSET
|
||||
{ 0, 0, 1, 1 }, // LEAP_MONTH
|
||||
{ 1, 1, 12, 12 }, // MAJOR_TERM
|
||||
{ 1, 1, 12, 12 }, // MINOR_TERM
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the minimum value for the given field.
|
||||
* e.g. for DAY_OF_MONTH, 1
|
||||
*
|
||||
* @param field The field whose minimum value is desired.
|
||||
*
|
||||
* @see java.util.Calendar#getMinimum
|
||||
*/
|
||||
public int getMinimum(int field)
|
||||
{
|
||||
return MinMax[field][0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the highest minimum value for the given field. For the Hebrew
|
||||
* calendar, this always returns the same result as <code>getMinimum</code>.
|
||||
*
|
||||
* @param field The field whose greatest minimum value is desired.
|
||||
*
|
||||
* @see #getMinimum
|
||||
*/
|
||||
public int getGreatestMinimum(int field)
|
||||
{
|
||||
return MinMax[field][1];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the maximum value for the given field.
|
||||
* e.g. for {@link #DAY_OF_MONTH DAY_OF_MONTH}, 30
|
||||
*
|
||||
* @param field The field whose maximum value is desired.
|
||||
*
|
||||
* @see #getLeastMaximum
|
||||
* @see #getActualMaximum
|
||||
*/
|
||||
public int getMaximum(int field)
|
||||
{
|
||||
return MinMax[field][3];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the lowest maximum value for the given field. For most fields,
|
||||
* this returns the same result as {@link #getMaximum getMaximum}. However,
|
||||
* for some fields this can be a lower number. For example,
|
||||
* the maximum {@link #DAY_OF_MONTH DAY_OF_MONTH} in the Hebrew caleandar varies
|
||||
* from month to month, so this method returns 29 while <code>getMaximum</code>
|
||||
* returns 30.
|
||||
*
|
||||
* @param field The field whose least maximum value is desired.
|
||||
*
|
||||
* @see #getMaximum
|
||||
* @see #getActualMaximum
|
||||
*/
|
||||
public int getLeastMaximum(int field)
|
||||
{
|
||||
return MinMax[field][2];
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// Date format stuff
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
protected DateFormat getDateTimeFormat(int dateStyle, int timeStyle, Locale loc) {
|
||||
debug("in ChineseCalendar.getDateTimeFormat(dateStyle,timeStyle,loc)");
|
||||
|
||||
return new ChineseDateFormat(this, dateStyle, timeStyle, loc);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// Internal utilities
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// Astronomy
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
private static long getSolstice(long utAfter, boolean next) {
|
||||
long result = 0;
|
||||
synchronized (astro) {
|
||||
astro.setTime(utAfter);
|
||||
result = astro.getSunTime(CalendarAstronomer.WINTER_SOLSTICE, next);
|
||||
}
|
||||
long localMillis = result + stdOffset(result);
|
||||
return result - (localMillis % DAY_MS);
|
||||
}
|
||||
|
||||
private static long newMoon(long utAfter, boolean next) {
|
||||
long result = 0;
|
||||
synchronized (astro) {
|
||||
astro.setTime(utAfter);
|
||||
result = astro.getMoonTime(CalendarAstronomer.NEW_MOON, next);
|
||||
}
|
||||
long localMillis = result + stdOffset(result);
|
||||
return result - (localMillis % DAY_MS);
|
||||
}
|
||||
|
||||
private static int getSolarTerm(long uTime) {
|
||||
synchronized (astro) {
|
||||
astro.setTime(uTime);
|
||||
return (int)(2 + Math.floor(astro.getSunLongitude() / (15*DEG_RAD))) % 24;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// Internal Data
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
// Timezone stuff
|
||||
private static final long BEIJING_OFFSET = 7*HOUR_MS + 45*MINUTE_MS + 40*SECOND_MS;
|
||||
private static final long MODERN_OFFSET = 8*HOUR_MS;
|
||||
private static final long TZ_EPOCH = -1293822000000L; // 1/1/1929 AD
|
||||
|
||||
// Start of year 1 of the Chinese calendar
|
||||
private static final long EPOCH = -145349319600000L; // 2/15/2635 BC
|
||||
|
||||
private static final double SYNODIC_MONTH = CalendarAstronomer.SYNODIC_MONTH;
|
||||
private static final double TROPICAL_YEAR = CalendarAstronomer.TROPICAL_YEAR;
|
||||
|
||||
// Need a GregorianCalendar object for doing time zone calculations
|
||||
private static GregorianCalendar gregorian = new GregorianCalendar();
|
||||
|
||||
|
||||
private static CalendarCache cache = new CalendarCache();
|
||||
|
||||
static private void debug(String str) {
|
||||
if (true) {
|
||||
System.out.println(str);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static SimpleDateFormat gmtDf = new SimpleDateFormat("MM/dd/yyyy HH:mm");
|
||||
static SimpleDateFormat bstDf = new SimpleDateFormat("MM/dd/yyyy HH:mm");
|
||||
static {
|
||||
gmtDf.setTimeZone(new SimpleTimeZone(0, "GMT"));
|
||||
bstDf.setTimeZone(new SimpleTimeZone(8*HOUR_MS, "BST"));
|
||||
}
|
||||
|
||||
private static String debug(long t) {
|
||||
Date d = new Date(t);
|
||||
return bstDf.format(d) + " BST [" + gmtDf.format(d) + " GMT]";
|
||||
}
|
||||
};
|
@ -1,5 +1,5 @@
|
||||
#
|
||||
# @(#)$RCSfile: GNUmakefile,v $ $Revision: 1.1 $ $Date: 2000/02/16 23:40:08 $
|
||||
# @(#)$RCSfile: GNUmakefile,v $ $Revision: 1.2 $ $Date: 2000/02/25 23:57:12 $
|
||||
#
|
||||
|
||||
TOPDIR= ../../../..
|
||||
@ -12,7 +12,6 @@ FILES_java= $(TARGDIR)/IBMCalendar.java \
|
||||
$(TARGDIR)/CalendarAstronomer.java \
|
||||
$(TARGDIR)/CalendarCache.java \
|
||||
$(TARGDIR)/BuddhistCalendar.java \
|
||||
$(TARGDIR)/ChineseCalendar.java \
|
||||
$(TARGDIR)/HebrewCalendar.java \
|
||||
$(TARGDIR)/IslamicCalendar.java \
|
||||
$(TARGDIR)/JapaneseCalendar.java \
|
||||
|
@ -1,5 +1,5 @@
|
||||
#
|
||||
# @(#)$RCSfile: makefile,v $ $Revision: 1.1 $ $Date: 2000/02/16 23:40:08 $
|
||||
# @(#)$RCSfile: makefile,v $ $Revision: 1.2 $ $Date: 2000/02/25 23:57:12 $
|
||||
#
|
||||
|
||||
TOPDIR= ../../../..
|
||||
@ -12,7 +12,6 @@ FILES_java= $(TARGDIR)/IBMCalendar.java \
|
||||
$(TARGDIR)/CalendarAstronomer.java \
|
||||
$(TARGDIR)/CalendarCache.java \
|
||||
$(TARGDIR)/BuddhistCalendar.java \
|
||||
$(TARGDIR)/ChineseCalendar.java \
|
||||
$(TARGDIR)/HebrewCalendar.java \
|
||||
$(TARGDIR)/IslamicCalendar.java \
|
||||
$(TARGDIR)/JapaneseCalendar.java \
|
||||
|
Loading…
Reference in New Issue
Block a user