/rust/registry/src/index.crates.io-1949cf8c6b5b557f/sofars-0.6.1/src/ts/dat.rs
Line | Count | Source |
1 | | /// For a given UTC date, calculate Delta(AT) = TAI-UTC. |
2 | | /// ``` |
3 | | /// :------------------------------------------: |
4 | | /// : : |
5 | | /// : IMPORTANT : |
6 | | /// : : |
7 | | /// : A new version of this function must be : |
8 | | /// : produced whenever a new leap second is : |
9 | | /// : announced. There are four items to : |
10 | | /// : change on each such occasion: : |
11 | | /// : : |
12 | | /// : 1) A new line must be added to the set : |
13 | | /// : of statements that initialize the : |
14 | | /// : array "changes". : |
15 | | /// : : |
16 | | /// : 2) The constant IYV must be set to the : |
17 | | /// : current year. : |
18 | | /// : : |
19 | | /// : 3) The "Latest leap second" comment : |
20 | | /// : below must be set to the new leap : |
21 | | /// : second date. : |
22 | | /// : : |
23 | | /// : 4) The "This revision" comment, later, : |
24 | | /// : must be set to the current date. : |
25 | | /// : : |
26 | | /// : Change (2) must also be carried out : |
27 | | /// : whenever the function is re-issued, : |
28 | | /// : even if no leap seconds have been : |
29 | | /// : added. : |
30 | | /// : : |
31 | | /// : Latest leap second: 2016 December 31 : |
32 | | /// : : |
33 | | /// :__________________________________________: |
34 | | /// ``` |
35 | | /// This function is part of the International Astronomical Union's |
36 | | /// SOFA (Standards of Fundamental Astronomy) software collection. |
37 | | /// |
38 | | /// Status: user-replaceable support function. |
39 | | /// |
40 | | /// Given: |
41 | | /// ``` |
42 | | /// iy int UTC: year (Notes 1 and 2) |
43 | | /// im int month (Note 2) |
44 | | /// id int day (Notes 2 and 3) |
45 | | /// fd double fraction of day (Note 4) |
46 | | /// ``` |
47 | | /// Returned: |
48 | | /// ``` |
49 | | /// deltat double TAI minus UTC, seconds |
50 | | /// ``` |
51 | | /// Returned (function value): |
52 | | /// ``` |
53 | | /// int status (Note 5): |
54 | | /// 1 = dubious year (Note 1) |
55 | | /// 0 = OK |
56 | | /// -1 = bad year |
57 | | /// -2 = bad month |
58 | | /// -3 = bad day (Note 3) |
59 | | /// -4 = bad fraction (Note 4) |
60 | | /// -5 = internal error (Note 5) |
61 | | /// ``` |
62 | | /// Notes: |
63 | | /// |
64 | | /// 1) UTC began at 1960 January 1.0 (JD 2436934.5) and it is improper |
65 | | /// to call the function with an earlier date. If this is attempted, |
66 | | /// zero is returned together with a warning status. |
67 | | /// |
68 | | /// Because leap seconds cannot, in principle, be predicted in |
69 | | /// advance, a reliable check for dates beyond the valid range is |
70 | | /// impossible. To guard against gross errors, a year five or more |
71 | | /// after the release year of the present function (see the constant |
72 | | /// IYV) is considered dubious. In this case a warning status is |
73 | | /// returned but the result is computed in the normal way. |
74 | | /// |
75 | | /// For both too-early and too-late years, the warning status is +1. |
76 | | /// This is distinct from the error status -1, which signifies a year |
77 | | /// so early that JD could not be computed. |
78 | | /// |
79 | | /// 2) If the specified date is for a day which ends with a leap second, |
80 | | /// the TAI-UTC value returned is for the period leading up to the |
81 | | /// leap second. If the date is for a day which begins as a leap |
82 | | /// second ends, the TAI-UTC returned is for the period following the |
83 | | /// leap second. |
84 | | /// |
85 | | /// 3) The day number must be in the normal calendar range, for example |
86 | | /// 1 through 30 for April. The "almanac" convention of allowing |
87 | | /// such dates as January 0 and December 32 is not supported in this |
88 | | /// function, in order to avoid confusion near leap seconds. |
89 | | /// |
90 | | /// 4) The fraction of day is used only for dates before the |
91 | | /// introduction of leap seconds, the first of which occurred at the |
92 | | /// end of 1971. It is tested for validity (0 to 1 is the valid |
93 | | /// range) even if not used; if invalid, zero is used and status -4 |
94 | | /// is returned. For many applications, setting fd to zero is |
95 | | /// acceptable; the resulting error is always less than 3 ms (and |
96 | | /// occurs only pre-1972). |
97 | | /// |
98 | | /// 5) The status value returned in the case where there are multiple |
99 | | /// errors refers to the first error detected. For example, if the |
100 | | /// month and day are 13 and 32 respectively, status -2 (bad month) |
101 | | /// will be returned. The "internal error" status refers to a |
102 | | /// case that is impossible but causes some compilers to issue a |
103 | | /// warning. |
104 | | /// |
105 | | /// 6) In cases where a valid result is not available, zero is returned. |
106 | | /// |
107 | | /// References: |
108 | | /// |
109 | | /// 1) For dates from 1961 January 1 onwards, the expressions from the |
110 | | /// file ftp://maia.usno.navy.mil/ser7/tai-utc.dat are used. |
111 | | /// |
112 | | /// 2) The 5ms timestep at 1961 January 1 is taken from 2.58.1 (p87) of |
113 | | /// the 1992 Explanatory Supplement. |
114 | | /// |
115 | | /// Called: |
116 | | /// iauCal2jd Gregorian calendar to JD |
117 | 0 | pub fn dat(iy: i32, im: i32, id: i32, fd: f64) -> Result<f64, i32> { |
118 | | // Reference dates (MJD) and drift rates (s/day), pre leap seconds |
119 | | const DRIFT: &[(f64, f64)] = &[ |
120 | | (37300.0, 0.0012960), |
121 | | (37300.0, 0.0012960), |
122 | | (37300.0, 0.0012960), |
123 | | (37665.0, 0.0011232), |
124 | | (37665.0, 0.0011232), |
125 | | (38761.0, 0.0012960), |
126 | | (38761.0, 0.0012960), |
127 | | (38761.0, 0.0012960), |
128 | | (38761.0, 0.0012960), |
129 | | (38761.0, 0.0012960), |
130 | | (38761.0, 0.0012960), |
131 | | (38761.0, 0.0012960), |
132 | | (39126.0, 0.0025920), |
133 | | (39126.0, 0.0025920), |
134 | | ]; |
135 | | |
136 | | // Number of Delta(AT) expressions before leap seconds were introduced |
137 | | const NERA1: usize = DRIFT.len(); |
138 | | |
139 | | // Dates and Delta(AT)s |
140 | | const CHANGES: &[(i32, i32, f64)] = &[ |
141 | | (1960, 1, 1.4178180), |
142 | | (1961, 1, 1.4228180), |
143 | | (1961, 8, 1.3728180), |
144 | | (1962, 1, 1.8458580), |
145 | | (1963, 11, 1.9458580), |
146 | | (1964, 1, 3.2401300), |
147 | | (1964, 4, 3.3401300), |
148 | | (1964, 9, 3.4401300), |
149 | | (1965, 1, 3.5401300), |
150 | | (1965, 3, 3.6401300), |
151 | | (1965, 7, 3.7401300), |
152 | | (1965, 9, 3.8401300), |
153 | | (1966, 1, 4.3131700), |
154 | | (1968, 2, 4.2131700), |
155 | | (1972, 1, 10.0), |
156 | | (1972, 7, 11.0), |
157 | | (1973, 1, 12.0), |
158 | | (1974, 1, 13.0), |
159 | | (1975, 1, 14.0), |
160 | | (1976, 1, 15.0), |
161 | | (1977, 1, 16.0), |
162 | | (1978, 1, 17.0), |
163 | | (1979, 1, 18.0), |
164 | | (1980, 1, 19.0), |
165 | | (1981, 7, 20.0), |
166 | | (1982, 7, 21.0), |
167 | | (1983, 7, 22.0), |
168 | | (1985, 7, 23.0), |
169 | | (1988, 1, 24.0), |
170 | | (1990, 1, 25.0), |
171 | | (1991, 1, 26.0), |
172 | | (1992, 7, 27.0), |
173 | | (1993, 7, 28.0), |
174 | | (1994, 7, 29.0), |
175 | | (1996, 1, 30.0), |
176 | | (1997, 7, 31.0), |
177 | | (1999, 1, 32.0), |
178 | | (2006, 1, 33.0), |
179 | | (2009, 1, 34.0), |
180 | | (2012, 7, 35.0), |
181 | | (2015, 7, 36.0), |
182 | | (2017, 1, 37.0), |
183 | | ]; |
184 | | |
185 | | // Number of Delta(AT) changes |
186 | | const NDAT: usize = CHANGES.len(); |
187 | | |
188 | | // Miscellaneous local variables |
189 | | let mut i: usize; |
190 | | let m: i32; |
191 | | let mut da: f64; |
192 | | |
193 | | // If invalid fraction of a day, set error status and give up. |
194 | 0 | if fd < 0.0 || fd > 1.0 { |
195 | 0 | return Err(-4); |
196 | 0 | } |
197 | | |
198 | | use crate::cal::cal2jd; |
199 | | // Convert the date into an MJD. |
200 | 0 | let j = cal2jd(iy, im, id); |
201 | | |
202 | | // If invalid year, month, or day, give up. |
203 | 0 | if let Err(e) = j { |
204 | 0 | return Err(e); |
205 | 0 | } |
206 | | |
207 | 0 | let (_, djm) = j.unwrap(); |
208 | | |
209 | | // If pre-UTC year, return zero (status 1 ignored). |
210 | 0 | if iy < CHANGES[0].0 { |
211 | 0 | return Ok(0.0); |
212 | 0 | } |
213 | | |
214 | | // Combine year and month to form a date-ordered integer... |
215 | 0 | m = 12 * iy + im; |
216 | | |
217 | | // ...and use it to find the preceding table entry. |
218 | 0 | i = NDAT - 1; |
219 | 0 | while i > 0 && m < (12 * CHANGES[i].0 + CHANGES[i].1) { |
220 | 0 | i -= 1; |
221 | 0 | } |
222 | | |
223 | | // Prevent underflow warnings. |
224 | 0 | if i == 0 && m < (12 * CHANGES[i].0 + CHANGES[i].1) { |
225 | 0 | return Err(-5); |
226 | 0 | } |
227 | | |
228 | | // Get the Delta(AT). |
229 | 0 | da = CHANGES[i].2; |
230 | | |
231 | | // If pre-1972, adjust for drift. |
232 | 0 | if i < NERA1 { |
233 | 0 | da += (djm + fd - DRIFT[i].0) * DRIFT[i].1; |
234 | 0 | } |
235 | | |
236 | | // Return the Delta(AT) value. |
237 | 0 | Ok(da) |
238 | 0 | } |