common: Add the time module.
[gps-watch.git] / src / common / time.rs
diff --git a/src/common/time.rs b/src/common/time.rs
new file mode 100644 (file)
index 0000000..0413c58
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2020 Tilman Sauerbeck (tilman at code-monkey de)
+ *
+ * Time::from_unix_time() adapted from musl's __secs_to_tm() which is
+ * Copyright © 2005-2020 Rich Felker, et al.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+pub struct Time {
+    seconds: i32,
+    minutes: i32,
+    hours: i32,
+    day: i32,
+    month: i32,
+    year: i32,
+}
+
+// 2000-03-01 (mod 400 year, immediately after feb29
+const LEAPOCH: i32 = (946684800 + 86400 * (31 + 29));
+
+const DAYS_PER_400Y: i32 = (365 * 400 + 97);
+const DAYS_PER_100Y: i32 = (365 * 100 + 24);
+const DAYS_PER_4Y  : i32 = (365 *   4 +  1);
+
+const DAYS_IN_MONTH : [i32; 12] = [ 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 31, 29 ];
+
+impl Time {
+    pub fn from_unix_time(u: u32) -> Option<Time> {
+        let t = u as i32;
+
+        let secs = t - LEAPOCH;
+        let mut days = secs / 86400;
+        let mut remsecs = secs % 86400;
+
+        if remsecs < 0 {
+            remsecs += 86400;
+            days -= 1;
+        }
+
+        let mut qc_cycles = days / DAYS_PER_400Y;
+        let mut remdays = days % DAYS_PER_400Y;
+
+        if remdays < 0 {
+            remdays += DAYS_PER_400Y;
+            qc_cycles -= 1;
+        }
+
+        let mut c_cycles = remdays / DAYS_PER_100Y;
+
+        if c_cycles == 4 {
+            c_cycles -= 1;
+        }
+
+        remdays -= c_cycles * DAYS_PER_100Y;
+
+        let mut q_cycles = remdays / DAYS_PER_4Y;
+
+        if q_cycles == 25 {
+            q_cycles -= 1;
+        }
+
+        remdays -= q_cycles * DAYS_PER_4Y;
+
+        let mut remyears = remdays / 365;
+
+        if remyears == 4 {
+            remyears -= 1;
+        }
+
+        remdays -= remyears * 365;
+
+        let mut years =
+            remyears + 4 * q_cycles + 100 * c_cycles + 400 * qc_cycles;
+
+        let mut months = 0;
+
+        while remdays >= DAYS_IN_MONTH[months as usize] {
+            remdays -= DAYS_IN_MONTH[months as usize];
+            months += 1;
+        }
+
+        if months >= 10 {
+            months -= 12;
+            years += 1;
+        }
+
+        if years + 100 > i32::max_value() || years + 100 < i32::min_value() {
+            None
+        } else {
+            Some(Time {
+                year: years + 100,
+                month: months + 2,
+                day: remdays + 1,
+                hours: remsecs / 3600,
+                minutes: remsecs / 60 % 60,
+                seconds: remsecs % 60,
+            })
+        }
+    }
+}