/*****************************************************************************\
 * 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.