📄 bigdate.java
字号:
* Year, -999,999 to +999,999, negative is BC, positive is AD, 0 is null. If I were rewriting this, I would likely
* encode year 1 BC as 0, and convert on output. That would simplify calculation over the 1AD -1BC barrrier.
*
* @noinspection WeakerAccess
*/
protected transient int yyyy = 0;
// -------------------------- PUBLIC STATIC METHODS --------------------------
/**
* Returns a BigDate object initialised to today's UTC (Greenwich GMT) date, in other words the date and time in
* Greenwich England right now without any summer time correction. It works even if Java's default Timezone is not
* configured correctly, but it requires your system clock accurately set to UTC time. Experiment setting your
* system date/time to various values and making sure you are getting the expected results. Note the date in the
* created object does not keep updating every time you reference it with methods like getOrdinal or getDD. You
* always get the date the object was created.
*
* @return BigDate object initialised to today, in Greenwich.
* @see #localToday
* @see #today
*/
public static BigDate UTCToday()
{
// 86,400,000 = 1000 * 60 * 60 * 24 = milliseconds per day
return new BigDate( ( int ) ( System.currentTimeMillis() / 86400000L ) );
}// end UTCToday
// p u b l i c m e t h o d s
/**
* calculate the age in years, months and days. To compute elapsed time between two dates, use the first as the
* birthDate and the second as the asof.
*
* @param birthDate usually the birth of a person.
* @param asof usually today, the day you want the age as of. asof must come after birthDate to get a
* meaningful result.
* @return array of three ints (not Integers). [0]=age in years, [1]=age in months, [2]=age in days.
* @see #localToday
* @see #today
* @see #UTCToday
*/
public static int[] age( BigDate birthDate, BigDate asof )
{
if ( birthDate.getOrdinal() >= asof.getOrdinal() )
{
return new int[] { 0, 0, 0 };
}
int birthYYYY = birthDate.getYYYY();
int birthMM = birthDate.getMM();
int birthDD = birthDate.getDD();
int asofYYYY = asof.getYYYY();
int asofMM = asof.getMM();
int asofDD = asof.getDD();
int ageInYears = asofYYYY - birthYYYY;
int ageInMonths = asofMM - birthMM;
int ageInDays = asofDD - birthDD;
if ( ageInDays < 0 )
{
// This does not need to be a while loop because
// birthDD is always less than daysInbirthMM month.
// Guaranteed after this single treatment, ageInDays will be >= 0.
// i.e. ageInDays = asofDD - birthDD + daysInBirthMM.
ageInDays += BigDate.daysInMonth( birthMM, birthYYYY );
ageInMonths--;
}
if ( ageInMonths < 0 )
{
ageInMonths += 12;
ageInYears--;
}
if ( birthYYYY < 0 && asofYYYY > 0 )
{
ageInYears--;
}
if ( ageInYears < 0 )
{
ageInYears = 0;
ageInMonths = 0;
ageInDays = 0;
}
int[] result = new int[3];
result[ 0 ] = ageInYears;
result[ 1 ] = ageInMonths;
result[ 2 ] = ageInDays;
return result;
}// end age
/**
* Get day of week for given ordinal. It is one-based starting with Sunday.
*
* @param ordinal days since Jan 1, 1970 to test.
* @return day of week 1=Sunday 2=Monday 3=Tuesday 4=Wednesday 5=Thursday 6=Friday 7=Saturday Compatible with Sun's
* 1=Calendar.SUNDAY Not compatible with BigDate.getDayOfWeek.
* @see #isoDayOfWeek
* @see #dayOfWeek
* @see #getCalendarDayOfWeek
*/
public static int calendarDayOfWeek( int ordinal )
{
return dayOfWeek( ordinal ) + 1;
}
/**
* Get 3-char abbreviation of a given day of the week
*
* @param dayOfWeek sunday = 0
* @return abbreviation for day of week, e.g. "sun", all lower case.
*/
public static String dayAbbr( int dayOfWeek )
{
return dayAbbr[ dayOfWeek ];
}
/**
* Get full name of given day of the week
*
* @param dayOfWeek sunday = 0
* @return name of day of week e.g. "Sunday"
*/
public static String dayName( int dayOfWeek )
{
return dayName[ dayOfWeek ];
}
/**
* Get day of week for given ordinal. Is it zero-based starting with Sunday.
*
* @param ordinal days since Jan 1, 1970 to test.
* @return day of week 0=Sunday 1=Monday 2=Tuesday 3=Wednesday 4=Thursday 5=Friday 6=Saturday WARNING: not
* compatible with 1=Calendar.SUNDAY
* @see #calendarDayOfWeek
* @see #isoDayOfWeek
* @see #getDayOfWeek
*/
public static int dayOfWeek( int ordinal )
{
// modulus in Java is "broken" for negative numbers
// so we adjust to make the dividend positive.
// By "broken" I mean the official rules for what
// is supposed to happen for negative dividends
// won't give the desired result in this case.
// See modulus in the Java glossary for more details.
return ( ordinal == NULL_ORDINAL )
? 0
: ( ( ordinal + SundayIsZeroAdjustment - MIN_ORDINAL ) % 7 );
}
/**
* How many days are there in a given month?
*
* @param mm month 1 to 12 (not 0 to 11 as in Sun's Date), no lead 0.
* @param leap true if you are interested in a leap year
* @return how many days are in that month
*/
public static int daysInMonth( int mm, boolean leap )
{
if ( mm != 2 )
{
return usual_DaysPerMonthTable[ mm - 1 ];
}
else
{
return leap ? 29 : 28;
}
}// end daysInMonth
/**
* How many days are there in a given month? o
*
* @param mm month 1 to 12 (not 0 to 11 as in Sun's Date), no lead 0.
* @param yyyy year of interest.
* @return how many days are in that month
*/
public static int daysInMonth( int mm, int yyyy )
{
if ( mm != 2 )
{
return usual_DaysPerMonthTable[ mm - 1 ];
}
else
{
return isLeap( yyyy ) ? 29 : 28;
}
}// end daysInMonth
/**
* Multiply then divide using floored rather than the usual truncated arithmetic, using a long intermediate.
*
* @param multiplicand one of two numbers to multiply together
* @param multiplier one of two numbers to multiply together
* @param divisor number to divide by
* @return (multiplicand * multiplier) / divisor
*/
public static int flooredMulDiv( int multiplicand,
int multiplier,
int divisor )
{
long result = ( long ) multiplicand * ( long ) multiplier;
if ( result >= 0 )
{
return ( int ) ( result / divisor );
}
else
{
return ( int ) ( ( result - divisor + 1 ) / divisor );
}
}// end flooredMulDiv
/**
* Embeds copyright notice
*
* @return copyright notice
* @noinspection SameReturnValue
*/
public static String getCopyright()
{
return "BigDate 5.1 freeware copyright (c) 1997-2008 Roedy Green, Canadian Mind Products, http://mindprod.com roedyg@mindprod.com";
}
/**
* Is the given year a leap year, considering history, mod 100 and mod 400 rules? By 1582, this excess of leap years
* had built up noticeably. At the suggestion of astronomers Luigi Lilio and Christopher Clavius, Pope Gregory XIII
* dropped 10 days from the calendar. Thursday 1582 October 4 Julian was followed immediately by Friday 1582 October
* 15 Gregorian. He decreed that every 100 years, a leap year should be dropped except that every 400 years the leap
* year should be restored. Only Italy, Poland, Portugual and Spain went along with the new calendar immediately.
* One by one other countries adopted it in different years. Britain and its territories (including the USA and
* Canada) adopted it in 1752. By then, 11 days had to be dropped. 1752 September 2 was followed immediately by 1752
* September 14. The Gregorian calendar is the most widely used scheme. This is the scheme endorsed by the US Naval
* observatory. It corrects the year to 365.2425. It gets ahead 1 day every 3289 years. For BC dates, the years the
* years 1, 5, 9 are leap years, not 4, 8, 12 as you might expect, from the general rule.
*
* @param yyyy year to test.
* @return true if the year is a leap year.
* @noinspection SimplifiableIfStatement
*/
public static boolean isLeap( int yyyy )
{
// if you change this code, make sure you make corresponding changes to
// jan01OfYear, toGregorian, MondayIsZeroAdjustment,
// SundayIsZeroAdjustment,
// AD_epochAdjustment and BC_epochAdjustment
// yyyy & 3 is a fast way of saying yyyy % 4
if ( yyyy < Leap100RuleYYYY )
{
if ( yyyy < 0 )
{
return ( ( yyyy + 1 ) & 3 ) == 0;
}
else
{
return ( yyyy & 3 ) == 0;
}
}
if ( ( yyyy & 3 ) != 0 )
{
return false;
}
if ( yyyy % 100 != 0 )
{
return true;
}
if ( yyyy < Leap400RuleYYYY )
{
return false;
}
return yyyy % 400 == 0;
}
/**
* Test to see if the given yyyy-mm-dd is a date as a String is legitimate. must have 4-digit years, and use dashes
* between the number and no sign Does extensive checks considering leap years, missing days etc.
*
* @param yyyy_mm_dd string of form "yyyy-mm-dd".
* @return true if that represents a valid date.
*/
public static boolean isValid( String yyyy_mm_dd )
{
try
{
if ( yyyy_mm_dd.length() != 10 )
{
return false;
}
int yyyy = Integer.parseInt( yyyy_mm_dd.substring( 0, 4 ) );
int mm = Integer.parseInt( yyyy_mm_dd.substring( 5, 7 ) );
int dd = Integer.parseInt( yyyy_mm_dd.substring( 8, 10 ) );
return BigDate.isValid( yyyy, mm, dd );
}
catch ( NumberFormatException e )
{
return false;
}
}
/**
* Test to see if the given yyyy, mm, dd date is legitimate. Does extensive checks considering leap years, missing
* days etc.
*
* @param yyyy -999,999 (BC) to +999,999 (AD)
* @param mm month 1 to 12 (not 0 to 11 as in Sun's Date), no lead 0.
* @param dd day 1 to 31, no lead 0.
* @return true if yyyy mm dd is a valid date.
* @noinspection SimplifiableIfStatement
*/
public static boolean isValid( int yyyy, int mm, int dd )
{
// null date 0000 00 00 is considered valid
// but otherwise year 0000 never happened.
if ( yyyy == 0 )
{
return ( mm == 0 ) && ( dd == 0 );
}
if ( ( yyyy < MIN_YEAR )
|| ( yyyy > MAX_YEAR )
|| ( mm < 1 )
|| ( mm > 12 )
|| ( dd < 1 )
|| ( dd > 31 ) )
{
return false;
}
// account for missing 10 days in 1582.
// Thursday 1582 October 4 Julian was followed
// immediately by Friday 1582 October 15
// Similarly for the British Calendar
if ( yyyy == OJC_lastYYYY
&& mm == OJC_lastMM
&& OJC_lastDD < dd
&& dd < GC_firstDD )
{
return false;
}
return dd <= daysInMonth( mm, yyyy );
}// end isValid
/**
* Get day of week 1 to 7 for this ordinal according to the ISO standard IS-8601. It is one-based starting with
* Monday.
*
* @param ordinal days since Jan 1, 1970 to test.
* @return day of week 1=Monday to 7=Sunday, 0 for null date. WARNING: not compatible with 1=Calendar.SUNDAY.
* @see BigDate#dayOfWeek(int)
*/
public static int isoDayOfWeek( int ordinal )
{
// modulus in Java is "broken" for negative numbers
// so we adjust to make the dividend positive.
// By "broken" I mean the official rules for what
// is supposed to happen for negative dividends
// won't give the desired result in this case.
// See modulus in the Java glossary for more details.
return ( ordinal == NULL_ORDINAL )
? 0
: ( ( ordinal + MondayIsZeroAdjustment - MIN_ORDINAL ) % 7 ) + 1;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -