1/* Copyright 2021 Go For It! developers
2*
3* This file is part of Go For It!.
4*
5* Go For It! is free software: you can redistribute it
6* and/or modify it under the terms of version 3 of the
7* GNU General Public License as published by the Free Software Foundation.
8*
9* Go For It! is distributed in the hope that it will be
10* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
11* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
12* Public License for more details.
13*
14* You should have received a copy of the GNU General Public License along
15* with Go For It!. If not, see http://www.gnu.org/licenses/.
16*/
17
18/**
19 * Helper class for DateTime instances without time or with floating time
20 */
21public class GOFI.Date {
22    private GLib.DateTime _dt;
23    private bool _has_time;
24    private bool _time_is_floating;
25
26    public GLib.DateTime dt {
27        get {
28            return _dt;
29        }
30    }
31
32    /**
33     * Should dt be interpreted as a DateTime value with a date.
34     */
35    public bool has_time {
36        get {
37            return _has_time;
38        }
39    }
40
41    /**
42     * Should dt be interpreted as a DateTime value with a timezone.
43     */
44    public bool time_is_floating {
45        get {
46            return _time_is_floating;
47        }
48    }
49
50    public Date (GLib.DateTime dt, bool has_time = false, bool time_is_floating = true) {
51        this._dt = dt;
52        this._has_time = has_time;
53        this._time_is_floating = time_is_floating;
54    }
55
56    public Date.from_ymd (int year, int month, int day) {
57        _dt = new DateTime.utc (year, month, day, 0, 0, 0.0);
58        this._has_time = false;
59        this._time_is_floating = true;
60    }
61
62    /**
63     * Returns DateTime contained in this converted to the timezone of tz.
64     * If this has a floating time this time will be applied without timezone
65     * conversions.
66     * If this doesn't have a time set the returned time will be set 00:00:00.
67     * If tz is null the local timezone will be used.
68     */
69    public GLib.DateTime to_timezone (TimeZone? tz) {
70        int year, month, day;
71        if (has_time) {
72            if (time_is_floating) {
73                dt.get_ymd (out year, out month, out day);
74                if (tz == null) {
75                    return new DateTime.local (
76                        year, month, day,
77                        dt.get_hour (), dt.get_minute (), dt.get_seconds ()
78                    );
79                }
80                return new DateTime (
81                    tz, year, month, day,
82                    dt.get_hour (), dt.get_minute (), dt.get_seconds ()
83                );
84            }
85            if (tz == null) {
86                return dt.to_local ();
87            }
88            return dt.to_timezone (tz);
89        }
90        dt.get_ymd (out year, out month, out day);
91        if (tz == null) {
92            return new DateTime.local (year, month, day, 0, 0, 0.0);
93        }
94        return new DateTime (tz, year, month, day, 0, 0, 0.0);
95    }
96
97    public int dt_compare_date (DateTime dt) {
98        int a_year, a_month, a_day;
99        int b_year, b_month, b_day;
100
101        this.dt.get_ymd (out a_year, out a_month, out a_day);
102        dt.get_ymd (out b_year, out b_month, out b_day);
103
104        int result = 0;
105
106        if ((result = a_year - b_year) != 0) {
107            return result;
108        }
109        if ((result = a_month - b_month) != 0) {
110            return result;
111        }
112        return a_day - b_day;
113    }
114
115    public int compare (Date date) {
116        return this.to_timezone (null).compare (date.to_timezone (null));
117    }
118
119    public int days_between (Date date) {
120        int a_year, a_month, a_day;
121        int b_year, b_month, b_day;
122        GLib.Date a_date = GLib.Date ();
123        GLib.Date b_date = GLib.Date ();
124
125        this.dt.get_ymd (out a_year, out a_month, out a_day);
126        dt.get_ymd (out b_year, out b_month, out b_day);
127
128        a_date.set_dmy (
129            (GLib.DateDay) a_day, (GLib.DateMonth) a_month, (GLib.DateYear) a_year
130        );
131        b_date.set_dmy (
132            (GLib.DateDay) b_day, (GLib.DateMonth) b_month, (GLib.DateYear) b_year
133        );
134
135        return a_date.days_between (b_date);
136    }
137}
138