@@ -2,15 +2,17 @@ local _ENV = mkmodule('datetime')
22
33--[[
44TODO: investigate applicability for adv mode.
5- if advmode then TU_PER_DAY = 86400 ? or only for cur_year_tick?
5+ if advmode then TICKS_PER_DAY = 86400 ? or only for cur_year_tick?
66advmod_TU / 72 = ticks
77--]]
88
9- local TU_PER_DAY = 1200
10- local TU_PER_MONTH = TU_PER_DAY * 28
11- local TU_PER_YEAR = TU_PER_MONTH * 12
12- local DAYS_IN_YEAR = 336
13- local MONTHS_IN_YEAR = 12
9+ -- are these locals better in DwarfCalendar?
10+ local DAYS_PER_MONTH = 28
11+ local DAYS_PER_YEAR = 336
12+ local MONTHS_PER_YEAR = 12
13+ local TICKS_PER_DAY = 1200
14+ local TICKS_PER_MONTH = TICKS_PER_DAY * DAYS_PER_MONTH
15+ local TICKS_PER_YEAR = TICKS_PER_MONTH * MONTHS_PER_YEAR
1416
1517local MONTHS = {
1618 ' Granite' ,
@@ -27,110 +29,209 @@ local MONTHS = {
2729 ' Obsidian' ,
2830}
2931
30- -- Ordinal suffix rules found here: https://en.wikipedia.org/wiki/Ordinal_indicator
31- local function getOrdinalSuffix (ordinal )
32- if (ordinal < 0 ) then
33- ordinal = math.abs (ordinal )
34- end
32+ DwarfCalendar = defclass (DwarfCalendar )
3533
36- local rem = (ordinal < 100 ) and (ordinal % 10 ) or (ordinal % 100 )
37- -- rem can be between 11 and 13 only when ordinal is > 100
38- if (ordinal >= 11 and ordinal <= 13 ) or (rem >= 11 and rem <= 13 ) then
39- return ' th'
34+ DwarfCalendar .ATTRS {
35+ year = 0 ,
36+ year_tick = 0 ,
37+ }
38+
39+ function DwarfCalendar :init ()
40+ self :normalize ()
41+ end
42+
43+ function DwarfCalendar :addTicks (ticks )
44+ self .year_tick = self .year_tick + ticks
45+ self :normalize ()
46+ end
47+
48+ function DwarfCalendar :addDays (days )
49+ self .year_tick = self .year_tick + self .daysToTicks (days )
50+ self :normalize ()
51+ end
52+
53+ function DwarfCalendar :addMonths (months )
54+ self .year_tick = self .year_tick + self .monthsToTicks (months )
55+ self :normalize ()
56+ end
57+
58+ function DwarfCalendar :addYears (years )
59+ self .year = self .year + years
60+ end
61+
62+ -- returns an integer pair: (year), (year tick count)
63+ function DwarfCalendar :getYears ()
64+ return self .year , self .year_tick
65+ end
66+
67+ -- returns days since beginning of a year, starting from zero
68+ function DwarfCalendar :ticksToDays ()
69+ return self .year_tick // TICKS_PER_DAY
70+ end
71+
72+ -- returns days since the beginning of a month, starting from zero
73+ function DwarfCalendar :ticksToDayOfMonth ()
74+ return self :ticksToDays () % DAYS_PER_MONTH
75+ end
76+
77+ -- returns months since the beginning of a year, starting from zero
78+ function DwarfCalendar :ticksToMonths ()
79+ return self .year_tick // TICKS_PER_MONTH
80+ end
81+
82+ -- returns ticks since the beginning of a day
83+ function DwarfCalendar :getDayTicks ()
84+ return self .year_tick % TICKS_PER_DAY
85+ end
86+
87+ -- returns ticks since the beginning of a month
88+ function DwarfCalendar :getMonthTicks ()
89+ return self .year_tick % TICKS_PER_MONTH
90+ end
91+
92+ function DwarfCalendar :normalize ()
93+ if (self .year_tick > TICKS_PER_YEAR ) then
94+ self .year = self .year + (self .year_tick // TICKS_PER_YEAR )
95+ self .year_tick = self .year_tick % TICKS_PER_YEAR
96+ elseif (self .year_tick < 0 ) then
97+ -- going backwards in time, subtract year by at least one.
98+ self .year = self .year - math.max (1 , math.abs (self .year_tick ) // TICKS_PER_YEAR )
99+ self .year_tick = self .year_tick % TICKS_PER_YEAR
40100 end
41- -- modulo again to handle the case when ordinal is > 100
42- return ({' st' , ' nd' , ' rd' })[rem % 10 ] or ' th'
43101end
44102
45- DateTime = defclass (DateTime )
103+ function DwarfCalendar :__add (other )
104+ if DEBUG then self :_debugOps (other ) end
105+ -- normalize() handles adjustments to year and year_tick
106+ return DwarfCalendar { year = (self .year + other .year ), year_tick = (self .year_tick + other .year_tick ) }
107+ end
46108
47- DateTime .ATTRS {
48- year = 0 ,
49- year_tick = 0 ,
50- }
109+ function DwarfCalendar :__sub (other )
110+ if DEBUG then self :_debugOps (other ) end
111+ -- normalize() handles adjustments to year and year_tick
112+ return DwarfCalendar { year = (self .year - other .year ) , year_tick = (self .year_tick - other .year_tick ) }
113+ end
114+
115+ function DwarfCalendar :_debugOps (other )
116+ print (' first: ' .. self .year ,self .year_tick )
117+ print (' second: ' .. other .year ,other .year_tick )
118+ end
51119
52- function DateTime :init (args )
53- -- TODO: normalize args, if needed
120+ -- utility functions
121+ function DwarfCalendar .daysToTicks (days )
122+ return days * TICKS_PER_DAY
54123end
55124
56- -- returns an integer pair: (date represented by days), (day tick count)
57- function DateTime :getDateAsDays ()
58- local d , dt = self :getDayOfYear ()
59- return self .year * DAYS_IN_YEAR + d , dt
125+ function DwarfCalendar .monthsToTicks (months )
126+ return months * TICKS_PER_MONTH
60127end
61128
62- -- returns an integer pair: (day of month), (day tick count)
129+ function DwarfCalendar .getMonthNames ()
130+ return MONTHS
131+ end
132+
133+
134+ DateTime = defclass (DateTime , DwarfCalendar )
135+
136+ -- returns an integer pair: (day of month starting from 1), (day tick count)
63137function DateTime :getDayOfMonth ()
64- local md = (self .year_tick % TU_PER_MONTH ) / TU_PER_DAY ) + 1
65- -- fetch day tick count
66- local _ , dt = self :getDayOfYear ()
67- return md , dt
138+ return self :ticksToDayOfMonth () + 1 , self :getDayTicks (self .year_tick )
68139end
69140
70141-- returns a string in ordinal form (e.g. 1st, 12th, 22nd, 101st, 111th, 133rd)
71142function DateTime :getDayOfMonthWithSuffix ()
72143 local d = self :getDayOfMonth ()
73- return tostring (d ).. getOrdinalSuffix (d )
144+ return tostring (d ).. self . getOrdinalSuffix (d )
74145end
75146
76- -- returns an integer pair: (current day of year), (day tick count)
147+ -- returns an integer pair: (current day of year, from 1 ), (day tick count)
77148function DateTime :getDayOfYear ()
78- local d = (self .year_tick // TU_PER_DAY ) + 1
79- return d , self .year_tick - (TU_PER_DAY * d )
80- end
81-
82- -- returns an integer pair: (date represented by months), (month tick count)
83- function DateTime :getDateAsMonths ()
84- local m , mt = self :getMonth ()
85- return self .year * MONTHS_IN_YEAR + m , mt
149+ return self :ticksToDays () + 1 , self :getDayTicks ()
86150end
87151
88- -- returns an integer pair: (current month of the year), (month tick count)
152+ -- returns an integer pair: (current month of the year, from 1 ), (month tick count)
89153function DateTime :getMonth ()
90- local m = (self .year_tick // TU_PER_MONTH ) + 1
91- return m , self .year_tick - (TU_PER_MONTH * m )
154+ return self :ticksToMonths () + 1 , self :getMonthTicks ()
92155end
93156
94157-- returns a string of the current month of the year
95158function DateTime :getNameOfMonth ()
96159 return MONTHS [self :getMonth ()] or error (" getMonth(): bad index?" )
97160end
98161
99- -- returns an integer pair: (year), (year tick count)
100- function DateTime :getYears ()
101- return self .year , self .year_tick
162+ function DateTime :toDuration ()
163+ return Duration { year = self .year , year_tick = self .year_tick }
102164end
103165
104166function DateTime :__add (other )
105167 if DEBUG then self :_debugOps (other ) end
106- if self .year_tick + other .year_tick > TU_PER_YEAR then
107- -- We add a year when year_tick delta is greater than a year.
108- return DateTime { year = (self .year + other .year + 1 ) , year_tick = (self .year_tick + other .year_tick - TU_PER_YEAR ) }
109- else
110- return DateTime { year = (self .year + other .year ) , year_tick = (self .year_tick + other .year_tick ) }
111- end
112- -- NOT REACHED
168+ -- normalize() handles adjustments to year and year_tick
169+ return DateTime { year = (self .year + other .year ), year_tick = (self .year_tick + other .year_tick ) }
113170end
114171
172+ -- might make sense to return a Duration here
115173function DateTime :__sub (other )
116174 if DEBUG then self :_debugOps (other ) end
117- if self .year_tick < other .year_tick then
118- -- We subtract a year when year_tick delta is less than a year.
119- return DateTime { year = (self .year - other .year - 1 ) , year_tick = (TU_PER_YEAR + self .year_tick - other .year_tick ) }
120- else
121- return DateTime { year = (self .year - other .year ) , year_tick = (self .year_tick - other .year_tick ) }
122- end
123- -- NOT REACHED
124- end
125-
126- function DateTime :_debugOps (other )
127- print (self .year ,self .year_tick )
128- print (other .year ,other .year_tick )
175+ -- normalize() handles adjustments to year and year_tick
176+ return DateTime { year = (self .year - other .year ) , year_tick = (self .year_tick - other .year_tick ) }
129177end
130178
131179-- Static functions
132180function DateTime .now ()
133181 return DateTime { year = df .global .cur_year , year_tick = df .global .cur_year_tick }
134182end
135183
184+ -- Ordinal suffix rules found here: https://en.wikipedia.org/wiki/Ordinal_indicator
185+ function DateTime .getOrdinalSuffix (ordinal )
186+ if (ordinal < 0 ) then
187+ ordinal = math.abs (ordinal )
188+ end
189+
190+ local rem = (ordinal < 100 ) and (ordinal % 10 ) or (ordinal % 100 )
191+ -- rem can be between 11 and 13 only when ordinal is > 100
192+ if (ordinal >= 11 and ordinal <= 13 ) or (rem >= 11 and rem <= 13 ) then
193+ return ' th'
194+ end
195+ -- modulo again to handle the case when ordinal is > 100
196+ return ({' st' , ' nd' , ' rd' })[rem % 10 ] or ' th'
197+ end
198+
199+ Duration = defclass (Duration , DwarfCalendar )
200+
201+ -- returns ticks since year zero
202+ function Duration :getTicks ()
203+ return self .year * TICKS_PER_YEAR + self .year_tick
204+ end
205+
206+ -- returns an integer pair: (days since year zero), (day tick count)
207+ function Duration :getDays ()
208+ return self .year * DAYS_PER_YEAR + self :ticksToDays (), self :getDayTicks ()
209+ end
210+
211+ -- returns an integer pair: (months since year zero), (month tick count)
212+ function Duration :getMonths ()
213+ return self .year * MONTHS_PER_YEAR + self :ticksToMonths (), self :getMonthTicks ()
214+ end
215+
216+ -- returns parts of an elapsed time:
217+ -- years,
218+ -- months, - since start of year
219+ -- days, - since start of month
220+ -- day tick count - since start of day
221+ function Duration :getYearsMonthsDays ()
222+ return self .year , self :ticksToMonths (), self :ticksToDayOfMonth (), self :getDayTicks ()
223+ end
224+
225+ function Duration :__add (other )
226+ if DEBUG then self :_debugOps (other ) end
227+ -- normalize() handles adjustments to year and year_tick
228+ return Duration { year = (self .year + other .year ), year_tick = (self .year_tick + other .year_tick ) }
229+ end
230+
231+ function Duration :__sub (other )
232+ if DEBUG then self :_debugOps (other ) end
233+ -- normalize() handles adjustments to year and year_tick
234+ return Duration { year = (self .year - other .year ) , year_tick = (self .year_tick - other .year_tick ) }
235+ end
236+
136237return _ENV
0 commit comments