aboutsummaryrefslogtreecommitdiff
path: root/src/openvic-simulation/types/Date.hpp
blob: 2bf08e88c584cbd822d86ba227bb6e05d75b59c4 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
#pragma once

#include <climits>
#include <cstdint>
#include <ostream>
#include <string>

#include "openvic-simulation/utility/Getters.hpp"
#include "openvic-simulation/utility/Utility.hpp"

namespace OpenVic {
   // A relative period between points in time, measured in days
   struct Timespan : ReturnByValueProperty {
      using day_t = int64_t;

   private:
      day_t days;

   public:
      Timespan(day_t value = 0);

      bool operator<(Timespan other) const;
      bool operator>(Timespan other) const;
      bool operator<=(Timespan other) const;
      bool operator>=(Timespan other) const;
      bool operator==(Timespan other) const;
      bool operator!=(Timespan other) const;

      Timespan operator+(Timespan other) const;
      Timespan operator-(Timespan other) const;
      Timespan operator*(day_t factor) const;
      Timespan operator/(day_t factor) const;
      Timespan& operator+=(Timespan other);
      Timespan& operator-=(Timespan other);
      Timespan& operator++();
      Timespan operator++(int);

      day_t to_int() const;
      explicit operator day_t() const;
      std::string to_string() const;
      explicit operator std::string() const;

      static Timespan from_years(day_t num);
      static Timespan from_months(day_t num);
      static Timespan from_days(day_t num);
   };
   std::ostream& operator<<(std::ostream& out, Timespan const& timespan);

   // Represents an in-game date
   // Note: Current implementation does not account for leap-years, or dates before Year 0
   struct Date : ReturnByValueProperty {
      using year_t = uint16_t;
      using month_t = uint8_t;
      using day_t = uint8_t;

      static constexpr Timespan::day_t MONTHS_IN_YEAR = 12;
      static constexpr Timespan::day_t DAYS_IN_YEAR = 365;
      static constexpr Timespan::day_t DAYS_IN_MONTH[MONTHS_IN_YEAR] { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
      static Timespan::day_t const* DAYS_UP_TO_MONTH;
      static month_t const* MONTH_FROM_DAY_IN_YEAR;

      static constexpr char SEPARATOR_CHARACTER = '.';
      static const std::string MONTH_NAMES[MONTHS_IN_YEAR];

   private:
      // Number of days since Jan 1st, Year 0
      Timespan timespan;

      static Timespan _date_to_timespan(year_t year, month_t month, day_t day);
      static Timespan::day_t const* generate_days_up_to_month();
      static month_t const* generate_month_from_day_in_year();

   public:
      // The Timespan is considered to be the number of days since Jan 1st, Year 0
      Date(Timespan total_days);
      // Year month day specification
      Date(year_t year = 0, month_t month = 1, day_t day = 1);

      year_t get_year() const;
      month_t get_month() const;
      day_t get_day() const;

      bool operator<(Date other) const;
      bool operator>(Date other) const;
      bool operator<=(Date other) const;
      bool operator>=(Date other) const;
      bool operator==(Date other) const;
      bool operator!=(Date other) const;

      Date operator+(Timespan other) const;
      Timespan operator-(Date other) const;
      Date& operator+=(Timespan other);
      Date& operator-=(Timespan other);
      Date& operator++();
      Date operator++(int);

      bool in_range(Date start, Date end) const;

      /* This returns a std::string const&, rather than a std::string_view, as it needs to be converted to a
       * godot::StringName in order to be localised, and std::string_view to a godot::StringName conversion requires an
       * intermediary std::string. */
      std::string const& get_month_name() const;
      std::string to_string() const;
      explicit operator std::string() const;
      // Parsed from string of the form YYYY.MM.DD
      static Date from_string(char const* str, char const* end, bool* successful = nullptr, bool quiet = false);
      static Date from_string(char const* str, size_t length, bool* successful = nullptr, bool quiet = false);
      static Date from_string(std::string_view str, bool* successful = nullptr, bool quiet = false);
   };
   std::ostream& operator<<(std::ostream& out, Date date);
}

namespace std {
   template<>
   struct hash<OpenVic::Date> {
      [[nodiscard]] size_t operator()(OpenVic::Date date) const {
         size_t result = 0;
         OpenVic::utility::perfect_hash(result, date.get_day(), date.get_month(), date.get_year());
         return result;
      }
   };
}