001/* 002 * Shredzone Commons - suncalc 003 * 004 * Copyright (C) 2017 Richard "Shred" Körber 005 * http://commons.shredzone.org 006 * 007 * Licensed under the Apache License, Version 2.0 (the "License"); 008 * you may not use this file except in compliance with the License. 009 * 010 * This program is distributed in the hope that it will be useful, 011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 013 */ 014package org.shredzone.commons.suncalc.util; 015 016import static java.lang.Math.floor; 017import static java.lang.Math.round; 018import static org.shredzone.commons.suncalc.util.ExtendedMath.PI2; 019import static org.shredzone.commons.suncalc.util.ExtendedMath.frac; 020 021import java.time.Instant; 022import java.time.ZonedDateTime; 023import java.util.Objects; 024 025/** 026 * This class contains a Julian Date representation of a date. 027 * <p> 028 * Objects are immutable and threadsafe. 029 */ 030public class JulianDate { 031 032 private final ZonedDateTime dateTime; 033 private final double mjd; 034 035 /** 036 * Creates a new {@link JulianDate}. 037 * 038 * @param time 039 * {@link ZonedDateTime} to use for the date. 040 */ 041 public JulianDate(ZonedDateTime time) { 042 dateTime = Objects.requireNonNull(time, "time"); 043 mjd = dateTime.toInstant().toEpochMilli() / 86400000.0 + 40587.0; 044 } 045 046 /** 047 * Returns a {@link JulianDate} of the current date and the given hour. 048 * 049 * @param hour 050 * Hour of this date. This is a floating point value. Fractions are used 051 * for minutes and seconds. 052 * @return {@link JulianDate} instance. 053 */ 054 public JulianDate atHour(double hour) { 055 return new JulianDate(dateTime.plusSeconds(round(hour * 60.0 * 60.0))); 056 } 057 058 /** 059 * Returns a {@link JulianDate} of the given modified Julian date. 060 * 061 * @param mjd 062 * Modified Julian Date 063 * @return {@link JulianDate} instance. 064 */ 065 public JulianDate atModifiedJulianDate(double mjd) { 066 Instant mjdi = Instant.ofEpochMilli(Math.round((mjd - 40587.0) * 86400000.0)); 067 return new JulianDate(ZonedDateTime.ofInstant(mjdi, dateTime.getZone())); 068 } 069 070 /** 071 * Returns a {@link JulianDate} of the given Julian century. 072 * 073 * @param jc 074 * Julian Century 075 * @return {@link JulianDate} instance. 076 */ 077 public JulianDate atJulianCentury(double jc) { 078 return atModifiedJulianDate(jc * 36525.0 + 51544.5); 079 } 080 081 /** 082 * Returns this {@link JulianDate} as {@link ZonedDateTime} object. 083 * 084 * @return {@link ZonedDateTime} of this {@link JulianDate}. 085 */ 086 public ZonedDateTime getDateTime() { 087 return dateTime; 088 } 089 090 /** 091 * Returns the Modified Julian Date. 092 * 093 * @return Modified Julian Date, UTC. 094 */ 095 public double getModifiedJulianDate() { 096 return mjd; 097 } 098 099 /** 100 * Returns the Julian Centuries. 101 * 102 * @return Julian Centuries, based on J2000 epoch, UTC. 103 */ 104 public double getJulianCentury() { 105 return (mjd - 51544.5) / 36525.0; 106 } 107 108 /** 109 * Returns the Greenwich Mean Sidereal Time of this Julian Date. 110 * 111 * @return GMST 112 */ 113 public double getGreenwichMeanSiderealTime() { 114 final double secs = 86400.0; 115 116 double mjd0 = floor(mjd); 117 double ut = (mjd - mjd0) * secs; 118 double t0 = (mjd0 - 51544.5) / 36525.0; 119 double t = (mjd - 51544.5) / 36525.0; 120 121 double gmst = 24110.54841 122 + 8640184.812866 * t0 123 + 1.0027379093 * ut 124 + (0.093104 - 6.2e-6 * t) * t * t; 125 126 return (PI2 / secs) * (gmst % secs); 127 } 128 129 /** 130 * Returns the earth's true anomaly of the current date. 131 * <p> 132 * A simple approximation is used here. 133 * 134 * @return True anomaly, in radians 135 */ 136 public double getTrueAnomaly() { 137 return PI2 * frac((dateTime.getDayOfYear() - 5.0) / 365.256363); 138 } 139 140 @Override 141 public String toString() { 142 return String.format("%dd %02dh %02dm %02ds", 143 (long) mjd, 144 (long) (mjd * 24 % 24), 145 (long) (mjd * 24 * 60 % 60), 146 (long) (mjd * 24 * 60 * 60 % 60)); 147 } 148 149}