/*****************************************************************************\
* AstroDate.java
\*****************************************************************************/
package com.mhuss.AstroLib;
import com.mhuss.Util.Str;
import java.util.GregorianCalendar;
import java.util.TimeZone;
// A simple support class, for unit testing only
class ATest {
public int year, month, day;
public double frac, jd;
ATest( int y, int m, int d, double f, double j ) {
year=y; month=m; day=d; frac=f; jd = j;
}
}
/**
* A support class for DateOps.
*
* This class stores a date/time value at a precision of one second.
* This date/time can be specified using either the Gregorian Calendar
* (by default) or the Julian Calendar.
*
* It also supports conversions to and from the Julian Day number.
*/
public class AstroDate {
/**
* Default constructor = epoch J2000 (noon on 1/1/2000)
*/
public AstroDate() {
day = 1; month = 1; year = 2000; second = 12 * Astro.SECONDS_PER_HOUR;
}
/**
* Literal (member by member) constructor
*
* @param day Day of the month (1...31)
* @param month Month of the year (1..12)
* @param year Year
* @param seconds Time in seconds past midnight. This must be in the
* range from 0 to Astro.SECONDS_PER_DAY-1.
*/
public AstroDate(int day, int month, int year, int seconds) {
this.day=day; this.month=month; this.year=year; this.second=seconds;
}
/**
* Explicit day, month, year, hour, minute, and second constructor
*
* @param day Day of the month (1...31)
* @param month Month of the year (1..12)
* @param year Year
* @param hour Hour of the day (0...23)
* @param min Minute of the hour (0...59)
* @param sec Second of the minute (0...59)
*/
public AstroDate(int day, int month, int year, int hour, int min, int sec) {
this.day=day; this.month=month; this.year=year;
this.second = hour*Astro.SECONDS_PER_HOUR + min*Astro.SECONDS_PER_MINUTE + sec;
}
/**
* Day, Month, Year constructor (time defaults to 00:00:00 = midnight)
*
* @param day Day of the month (1...31)
* @param month Month of the year (1..12)
* @param year Year
*/
public AstroDate(int day, int month, int year) {
this.day = day; this.month=month; this.year=year; this.second=0;
}
/**
* Day, Month, Year + fraction of a day constructor
*
* @param day Day of the month
* @param month Month of the year
* @param year Year
* @param dayFraction Fraction of the day
* This must be greater than or equal to 0.0 and less
* than 1.0.
*/
public AstroDate(int day, int month, int year, double dayFraction) {
this.day=day; this.month=month; this.year=year;
this.second=dayFraction * Astro.SECONDS_PER_DAY;
}
/**
* Julian Day constructor.
*
* @param jd Julian day number
*/
public AstroDate( double jd ) {
// The conversion formulas and magic numbers are from Meeus,
// Chapter 7.
jd = jd +0.5; // Einfugung Strickling
double Z = Math.floor(jd);
double F = jd - Z;
double A = Z;
if ( Z >= 2299161D ) {
int a = (int)(( Z - 1867216.25 )/Astro.TO_CENTURIES);
A += 1 + a - a/4;
}
double B = A + 1524;
int C = (int)((B-122.1)/365.25);
int D = (int)(C * 365.25);
int E = (int)((B-D)/30.6001);
double exactDay = F + B - D - (int)(30.6001*E);
day = (int)exactDay;
month = (E<14) ? E-1 : E-13;
year = C - 4715;
if (month>2)
year--;
second = (exactDay - day) * Astro.SECONDS_PER_DAY;
}
//-------------------------------------------------------------------------
// functions
//-------------------------------------------------------------------------
/**
* Convert an AstroDate to a Julian Day.
*
* @param ad The date to convert
* @param julian true = Julian calendar, else Gregorian
*
* @return The Julian Day that corresponds to the specified AstroDate
*/
public static double jd( AstroDate ad, boolean julian ) {
// The conversion formulas and magic numbers are from Meeus,
// Chapter 7.
int D = ad.day;
int M = ad.month;
int Y = ad.year;
if ( M < 3 ) {
Y--;
M += 12;
}
int A = Y/100;
int B = julian ? 0 : 2 - A + A/4;
double dayFraction = ad.second / Astro.SECONDS_PER_DAY;
return dayFraction
+ (int)(365.25D * (Y + 4716))
+ (int)(30.6001 * (M + 1))
+ D + B - 1524.5;
}
/**
* Convert an AstroDate to a Julian Day.
* Assumes the AstroDate is specified using the Gregorian calendar.
*
* @param ad The date to convert
*
* @return The Julian Day that corresponds to the specified
* AstroDate
*/
public static double jd( AstroDate ad ) {
return jd( ad, false );
}
/**
* Convert this instance of AstroDate to a Julian Day.
*
* @param julian true = Julian calendar, else Gregorian
*
* @return The Julian Day that corresponds to this AstroDate instance
*/
public double jd(boolean julian) {
return jd( this, julian );
}
/**
* Convert this instance of AstroDate to a Julian Day.
* Assumes the AstroDate is specified using the Gregorian calendar.
*
* @return The Julian Day that corresponds to this AstroDate instance
*/
public double jd() {
return jd( this, false );
}
//-------------------------------------------------------------------------
// accessors - NOTE: These do no sanity checking
//-------------------------------------------------------------------------
/**
* Get the year.
*
* @return The year part of this instance of AstroDate
*/
public int year() { return year; }
/**
* Set the year.
*
* @param The year part of this instance of AstroDate
*/
void setYear(int y) { year = y; }
/**
* Get the month.
*
* @return The month part of this instance of AstroDate (1..12)
*/
public int month() { return month; }
/**
* Set the month.
*
* @param The month part of this instance of AstroDate (1..12)
* Value is not checked!
*/
void setMonth(int m) { month = m; }
/**
* Get the day.
*
* @return The day part of this instance of AstroDate (1..31)
*/
public int day() { return day; }
/**
* Set the day.
*
* @param The day part of this instance of AstroDate (1..31)
* Value is not checked!
*/
void setDay(int d) { day = d; }
/**
* Get the Hour.
* This function truncates, and does not round up to nearest hour.
* For example, this function will return '1' at all times from
* 01:00:00 to 01:59:59 inclusive.
*
* @return The hour of the day for this instance of AstroDate,
* not rounded
*/
public int hour() {
return (int)(second / Astro.SECONDS_PER_HOUR);
}
/**
* Get the rounded hour.
* Returns the hour of the day rounded to nearest hour.
* For example, this function will return '1' at times 01:00:00 to
* 01:29:59, and '2' at times 01:30:00 to 01:59:59.
*
* @return The hour of the day for this instance of AstroDate,
* rounded to the nearest hour.
*/
public int hourRound() {
return (int)((second / Astro.SECONDS_PER_HOUR) + Astro.ROUND_UP);
}
/**
* Get the minute.
*
* This function truncates, and does not round up to nearest minute.
* For example, this function will return 20 at all times from
* 1:20:00 to 1:20:59 inclusive.
*
* @return The minute of the hour for this instance of AstroDate,
* not rounded.
*/
public int minute() {
return (int)((second - (hour() * Astro.SECONDS_PER_HOUR))/Astro.SECONDS_PER_MINUTE);
}
/**
* Get the rounded minute.
*
* Returns the minute of the hour for this instance of AstroDate,
* rounded to nearest minute.
* For example, this function will return 20 at times 1:20:00 to
* 1:20:29, and 21 at times 1:20:30 to 1:20:59.
*
* @return The minute of the hour for this instance of AstroDate,
* rounded to the nearest minute.
*/
public int minuteRound() {
return (int)(((second - (hour() * Astro.SECONDS_PER_HOUR))/Astro.SECONDS_PER_MINUTE) + Astro.ROUND_UP);
}
/**
* Get the second.
*
* @return The second of the minute for this instance of AstroDate.
*
*/
public int second() {
return (int)(second - (hour() * Astro.SECONDS_PER_HOUR) - (minute() * Astro.SECONDS_PER_MINUTE));
}
/**
* Convert this AstroDate instance to a GregorianCalendar.
*
* @return An instance of java.util.GregorianCalendar built
* using this instance of AstroDate.
*/
public GregorianCalendar toGCalendar() {
return new GregorianCalendar( year, month-1, day, hour(), minute(), second() );
}
/**
* Convert this AstroDate instance to a String,
* formatted to the minute.
* This function rounds the exact time to the nearest minute.
*
* The format of the returned string is YYYY-MM-DD hh:mm.
*
* @return A formatted date/time String
*/
public String toMinString() {
return Str.fmt( year, 4, '-' ) + Str.fmt( month, '-' ) +
Str.fmt( day, ' ' ) + Str.fmt( hour(), ':' ) +
Str.fmt( minuteRound());
}
/**
* Convert this AstroDate instance to a String formatted
* to the minute, with Time Zone indicator.
* Rounds the time to the nearest minute.
*
* The format of the returned string is YYYY-MM-DD hh:mm TZ,
* where TZ is a locale-specific timezone name (e.g., "EST").
*
* @return A formatted date/time String
*/
public String toMinStringTZ() {
TimeZone tz = TimeZone.getDefault();
return toMinString() + ' ' +
tz.getDisplayName( TimeOps.dstOffset(toGCalendar()) != 0, TimeZone.SHORT);
}
/**
* Convert this AstroDate instance to a String.
*
* The format of the returned string is YYYY-MM-DD hh:mm:ss.
*
* @return A formatted date/time String
*/
public String toString() {
return "" +
Str.fmt( year, 4, '-' ) + Str.fmt( month, '-' ) +
Str.fmt( day, ' ' ) + Str.fmt( hour(), ':' ) +
Str.fmt( minute(), ':' ) + Str.fmt( second() );
}
/**
* Convert this AstroDate instance to a String,
* with Time Zone indicator.
*
* The format of the returned string is YYYY-MM-DD hh:mm:ss TZ,
* where TZ is a locale-specific timezone name (e.g., "EST")
*
* @return A formatted date/time String
*/
public String toStringTZ() {
TimeZone tz = TimeZone.getDefault();
return toString() + ' ' +
tz.getDisplayName( TimeOps.dstOffset(toGCalendar()) != 0, TimeZone.SHORT);
}
//-------------------------------------------------------------------------
/**
* day of the month
*/
int day;
/**
* month of the year
*/
int month;
/**
* year
*/
int year;
/**
* Seconds past midnight == day fraction.
* Valid values range from 0 to Astro.SECONDS_PER_DAY-1.
*/
double second;
//-------------------------------------------------------------------------
/**
* (for unit testing only)
*/
public static void main( String args[] ) {
System.out.println( "AstroDate Test" );
ATest at[] = new ATest[7];
// data from Meeus
at[0] = new ATest( 2000, 1, 1, .5, 2451545. );
at[1] = new ATest( 1987, 6, 19, .5, 2446966. );
at[2] = new ATest( 1900, 1, 1, .0, 2415020.5 );
at[3] = new ATest( 1600, 12, 31, .0, 2305812.5 );
at[4] = new ATest( 837, 4, 10, .3, 2026871.8 );
at[5] = new ATest( -1000, 7, 12, .5, 1356001. );
at[6] = new ATest( -4712, 1, 1, .5, 0. );
for (int i=0; i<7; i++) {
AstroDate ad = new AstroDate( at[i].day, at[i].month, at[i].year, at[i].frac );
double jdm = ad.jd();
double jdg = 0; //** circular reference ** DateOps.dmyToDoubleDay(ad);
System.out.println(
"year: " + at[i].year + ", expected: " + at[i].jd +
", jd(m)=" + jdm + ", jd(g)=" + jdg );
}
//jd = 2305812.5;
//AstroDate ad = new AstroDate( jd );
//System.out.println( "" + ad.year + '/' + ad.month + '/' + ad.day + ad.second / AstroDate.SECONDS_PER_DAY );
//GregorianCalendar gc = DateOps.jdToCal( );
//System.out.println( DateU.dateTime(gc) );
}
}
Ads help maintain this website.