001/* 002 * Geotoolkit.org - An Open Source Java GIS Toolkit 003 * http://www.geotoolkit.org 004 * 005 * (C) 2000-2012, Open Source Geospatial Foundation (OSGeo) 006 * (C) 2009-2012, Geomatys 007 * 008 * This library is free software; you can redistribute it and/or 009 * modify it under the terms of the GNU Lesser General Public 010 * License as published by the Free Software Foundation; 011 * version 2.1 of the License. 012 * 013 * This library is distributed in the hope that it will be useful, 014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 016 * Lesser General Public License for more details. 017 * 018 * NOTE: permission has been given to the JScience project (http://www.jscience.org) 019 * to distribute this file under BSD-like license. 020 */ 021package edu.wisc.ssec.mcidasv.util; 022 023import java.util.Date; 024import java.util.Locale; 025import java.util.TimeZone; 026import java.text.DateFormat; 027import java.text.ParseException; 028import java.text.SimpleDateFormat; 029import java.io.PrintStream; 030 031 032/** 033 * Approximations de quelques calculs astronomiques relatifs aux calendriers terrestres. 034 * Les différents cycles astronomiques (notamment le jour, le mois et l'année) ne sont pas 035 * constants. Par exemple, la longueur de l'année tropicale (le nombre moyen de jours entre 036 * deux équinoxes vernales) était d'environ 365,242196 jours en 1900 et devrait être d'environ 037 * 365,242184 jours en 2100, soit un changement d'environ 1 seconde. Cette classe permet de 038 * calculer la longueur d'une année ou d'un mois à une date spécifiée. Toutefois, il est 039 * important de noter que les intervalles de temps calculés par les méthodes de cette classe 040 * sont des <strong>moyennes</strong>. Pour une année en particulier, l'intervalle de temps 041 * d'un équinoxe vernale au prochain peut s'écarter de cette moyenne de plusieurs minutes. 042 * <p> 043 * Les calculs de la longueur de l'année tropicale sont basés sur les travaux de Laskar (1986). 044 * Les calculs de la longueur des mois synodiques sont basés sur les travaux de Chapront-Touze et 045 * Chapront (1988).On peut lire plus de détails au sujet des calendrier terrestre au site 046 * <a href="http://webexhibits.org/calendars/year-astronomy.html">http://webexhibits.org/calendars/year-astronomy.html</a> 047 * ainsi que 048 * <a href="http://www.treasure-troves.com/astro/TropicalYear.html">http://www.treasure-troves.com/astro/TropicalYear.html</a>. 049 * 050 * @author Martin Desruisseaux (IRD) 051 * @version 3.00 052 * 053 * @since 2.0 054 * @module 055 */ 056public final class Calendar { 057 /** 058 * Nombre de millisecondes dans une journée. Cette constante est 059 * utilisée pour convertir des intervalles de temps du Java en 060 * nombre de jours. 061 */ 062 private static final double MILLIS_IN_DAY = 1000*60*60*24; 063 064 /** 065 * Jour julien correspondant à l'époch du Java (1er janvier 1970 à minuit). 066 * Cette constante est utilisée pour convertir des dates du Java en jour 067 * julien. 068 * 069 * La valeur {@link #julianDay} du 1er janvier 2000 00:00 GMT est 2451544.5 jours. 070 * La valeur {@link Date#getTime} du 1er janvier 2000 00:00 GMT est 10957 jours. 071 */ 072 private static final double JULIAN_DAY_1970 = 2451544.5-10957; 073 074 /** 075 * Do not allow instantiation of this class. 076 */ 077 private Calendar() { 078 } 079 080 /** 081 * Returns the julian day of the given date. This is the number of days elapsed since 082 * January 1st, 4713 before J.C. at noon GMT. This is named after <cite>Julius Scaliger</cite>, 083 * not to be confused to the number of days elapsed since the beginning of the year (named after 084 * <cite>Julius Caesar</cite>). 085 * 086 * @param time The time for which to evaluate the julian day. 087 * @return Number of days elapsed since January 1st, 4713 before J.C. at noon GMT. 088 */ 089 public static double julianDay(final Date time) { 090 return julianDay(time.getTime()); 091 } 092 093 /** 094 * Computes the {@linkplain #julianDay(Date) julian day}. 095 * 096 * @param time The date in milliseconds elapsed since January 1st, 1970. 097 */ 098 static double julianDay(final long time) { 099 return (time/MILLIS_IN_DAY) + JULIAN_DAY_1970; 100 } 101 102 /** 103 * Retourne le nombre de siècles écoulés depuis le 1 janvier 2000 à midi. 104 * Cette information est utilisée dans les formules de Laskar (1986) pour 105 * calculer la longueur d'une année tropicale, ainsi que par Chapront-Touze 106 * et Chapront (1988) pour la longueur d'un mois synodique. 107 */ 108 static double julianCentury(final Date time) { 109 return ((time.getTime() / MILLIS_IN_DAY) + (JULIAN_DAY_1970 - 2451545.0)) / 36525; 110 } 111 112 /** 113 * Retourne la longueur de l'année tropicale. L'année tropicale est définie comme l'intervalle 114 * moyen entre deux équinoxes vernales (autour du 21 mars dans l'hémisphère nord). Il correspond 115 * au cycle des saisons. Cet intervalle de temps est une <strong>moyenne</strong>. Un cycle réel 116 * peut s'écarter de plusieurs minutes de cette moyenne. Notez aussi qu'une année tropicale 117 * n'est pas identique à une année sidérale, qui est le temps requis par la Terre pour compléter 118 * un orbite autour du Soleil. En l'an 2000, l'année tropicale avait une longueur d'environ 119 * 365,2422 jours tandis que l'année sidérale avait une longueur de 365,2564 jours. 120 * 121 * @param time A date in the year for which to compute the length. 122 * @return The tropical length of the given year. 123 */ 124 public static double tropicalYearLength(final Date time) { 125 final double T = julianCentury(time); 126 return 365.2421896698 + T*(-0.00000615359 + T*(-7.29E-10 + T*(2.64E-10))); 127 } 128 129 /** 130 * Retourne la longueur du mois synodique. Le mois synodique est l'intervalle de temps moyen 131 * entre deux conjonctions de la lune et du soleil. Il correspond au cycle des phases de la 132 * lune. Cet intervalle de temps est une <strong>moyenne</strong>. Un cycle réel peut s'écarter 133 * de plusieurs heures de cette moyenne. 134 * 135 * @param time A date in the month for which to compute the length. 136 * @return The synodic length of the given month. 137 */ 138 public static double synodicMonthLength(final Date time) { 139 final double T=julianCentury(time); 140 return 29.5305888531 + T*(0.00000021621 + T*(-3.64E-10)); 141 } 142 143 /** 144 * Returns a date format to be used by the command line tools. 145 */ 146 static DateFormat getDateFormat() { 147 final DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.CANADA); 148 format.setTimeZone(TimeZone.getTimeZone("UTC")); 149 return format; 150 } 151 152 /** 153 * Prints the length of a tropical year and a synodic month for the given date. 154 * Cette application peut être lancée avec la syntaxe suivante: 155 * This application can be launch from the command line as below: 156 * 157 * {@preformat shell 158 * java org.geotoolkit.nature.Calendar [date] 159 * } 160 * 161 * where <var>date</var> is an optional argument specifying the date and time in the 162 * {@code "yyyy-MM-dd HH:mm:ss"} format, UTC time zone. If this argument is omitted, 163 * then the current time is used. 164 * 165 * @param args The command line argument. 166 * @throws ParseException If the date is not properly formatted. 167 */ 168 public static void main(final String[] args) throws ParseException { 169 final DateFormat format = getDateFormat(); 170 final Date time = (args.length != 0) ? format.parse(args[0]) : new Date(); 171 final PrintStream out = System.out; 172 out.print("Date (UTC) : "); out.println(format.format(time)); 173 out.print("Tropical year: "); out.println(tropicalYearLength(time)); 174 out.print("Synodic month: "); out.println(synodicMonthLength(time)); 175 } 176}