0413c5880d06f2fea126d084eb88a7f518a9bc84
[gps-watch.git] / src / common / time.rs
1 /*
2  * Copyright (c) 2020 Tilman Sauerbeck (tilman at code-monkey de)
3  *
4  * Time::from_unix_time() adapted from musl's __secs_to_tm() which is
5  * Copyright © 2005-2020 Rich Felker, et al.
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining
8  * a copy of this software and associated documentation files (the
9  * "Software"), to deal in the Software without restriction, including
10  * without limitation the rights to use, copy, modify, merge, publish,
11  * distribute, sublicense, and/or sell copies of the Software, and to
12  * permit persons to whom the Software is furnished to do so, subject to
13  * the following conditions:
14  *
15  * The above copyright notice and this permission notice shall be
16  * included in all copies or substantial portions of the Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
22  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25  */
26
27 pub struct Time {
28     seconds: i32,
29     minutes: i32,
30     hours: i32,
31     day: i32,
32     month: i32,
33     year: i32,
34 }
35
36 // 2000-03-01 (mod 400 year, immediately after feb29
37 const LEAPOCH: i32 = (946684800 + 86400 * (31 + 29));
38
39 const DAYS_PER_400Y: i32 = (365 * 400 + 97);
40 const DAYS_PER_100Y: i32 = (365 * 100 + 24);
41 const DAYS_PER_4Y  : i32 = (365 *   4 +  1);
42
43 const DAYS_IN_MONTH : [i32; 12] = [ 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 31, 29 ];
44
45 impl Time {
46     pub fn from_unix_time(u: u32) -> Option<Time> {
47         let t = u as i32;
48
49         let secs = t - LEAPOCH;
50         let mut days = secs / 86400;
51         let mut remsecs = secs % 86400;
52
53         if remsecs < 0 {
54             remsecs += 86400;
55             days -= 1;
56         }
57
58         let mut qc_cycles = days / DAYS_PER_400Y;
59         let mut remdays = days % DAYS_PER_400Y;
60
61         if remdays < 0 {
62             remdays += DAYS_PER_400Y;
63             qc_cycles -= 1;
64         }
65
66         let mut c_cycles = remdays / DAYS_PER_100Y;
67
68         if c_cycles == 4 {
69             c_cycles -= 1;
70         }
71
72         remdays -= c_cycles * DAYS_PER_100Y;
73
74         let mut q_cycles = remdays / DAYS_PER_4Y;
75
76         if q_cycles == 25 {
77             q_cycles -= 1;
78         }
79
80         remdays -= q_cycles * DAYS_PER_4Y;
81
82         let mut remyears = remdays / 365;
83
84         if remyears == 4 {
85             remyears -= 1;
86         }
87
88         remdays -= remyears * 365;
89
90         let mut years =
91             remyears + 4 * q_cycles + 100 * c_cycles + 400 * qc_cycles;
92
93         let mut months = 0;
94
95         while remdays >= DAYS_IN_MONTH[months as usize] {
96             remdays -= DAYS_IN_MONTH[months as usize];
97             months += 1;
98         }
99
100         if months >= 10 {
101             months -= 12;
102             years += 1;
103         }
104
105         if years + 100 > i32::max_value() || years + 100 < i32::min_value() {
106             None
107         } else {
108             Some(Time {
109                 year: years + 100,
110                 month: months + 2,
111                 day: remdays + 1,
112                 hours: remsecs / 3600,
113                 minutes: remsecs / 60 % 60,
114                 seconds: remsecs % 60,
115             })
116         }
117     }
118 }