Skip to content

Commit ff93ade

Browse files
committed
new datetime API
1 parent e53632a commit ff93ade

File tree

1 file changed

+240
-0
lines changed

1 file changed

+240
-0
lines changed

library/lua/datetime.lua

Lines changed: 240 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,240 @@
1+
local _ENV = mkmodule('datetime')
2+
3+
--[[
4+
TODO: investigate applicability for adv mode.
5+
if advmode then TICKS_PER_DAY = 86400 ? or only for cur_year_tick?
6+
advmod_TU / 72 = ticks
7+
--]]
8+
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
16+
17+
local MONTHS = {
18+
'Granite',
19+
'Slate',
20+
'Felsite',
21+
'Hematite',
22+
'Malachite',
23+
'Galena',
24+
'Limestone',
25+
'Sandstone',
26+
'Timber',
27+
'Moonstone',
28+
'Opal',
29+
'Obsidian',
30+
}
31+
32+
DwarfCalendar = defclass(DwarfCalendar)
33+
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+
-- Lua's modulo operator applies floor division,
100+
-- hence year_tick will always be positive after assignment
101+
-- equivalent to: year_tick - (TICKS_PER_YEAR * (year_tick // TICKS_PER_YEAR))
102+
self.year_tick = self.year_tick % TICKS_PER_YEAR
103+
end
104+
end
105+
106+
function DwarfCalendar:__add(other)
107+
if DEBUG then self:_debugOps(other) end
108+
-- normalize() handles adjustments to year and year_tick
109+
return DwarfCalendar{ year = (self.year + other.year), year_tick = (self.year_tick + other.year_tick) }
110+
end
111+
112+
function DwarfCalendar:__sub(other)
113+
if DEBUG then self:_debugOps(other) end
114+
-- normalize() handles adjustments to year and year_tick
115+
return DwarfCalendar{ year = (self.year - other.year) , year_tick = (self.year_tick - other.year_tick) }
116+
end
117+
118+
function DwarfCalendar:_debugOps(other)
119+
print('first: '..self.year,self.year_tick)
120+
print('second: '..other.year,other.year_tick)
121+
end
122+
123+
-- utility functions
124+
function DwarfCalendar.daysToTicks(days)
125+
return days * TICKS_PER_DAY
126+
end
127+
128+
function DwarfCalendar.monthsToTicks(months)
129+
return months * TICKS_PER_MONTH
130+
end
131+
132+
function DwarfCalendar.getMonthNames()
133+
return MONTHS
134+
end
135+
136+
137+
DateTime = defclass(DateTime, DwarfCalendar)
138+
139+
-- returns an integer pair: (day of month starting from 1), (day tick count)
140+
function DateTime:getDayOfMonth()
141+
return self:ticksToDayOfMonth() + 1, self:getDayTicks()
142+
end
143+
144+
-- returns a string in ordinal form (e.g. 1st, 12th, 22nd, 101st, 111th, 133rd)
145+
function DateTime:getDayOfMonthWithSuffix()
146+
local d = self:getDayOfMonth()
147+
return tostring(d)..self.getOrdinalSuffix(d)
148+
end
149+
150+
-- returns an integer pair: (current day of year, from 1), (day tick count)
151+
function DateTime:getDayOfYear()
152+
return self:ticksToDays() + 1, self:getDayTicks()
153+
end
154+
155+
-- returns an integer pair: (current month of the year, from 1), (month tick count)
156+
function DateTime:getMonth()
157+
return self:ticksToMonths() + 1, self:getMonthTicks()
158+
end
159+
160+
-- returns a string of the current month of the year
161+
function DateTime:getNameOfMonth()
162+
return MONTHS[self:getMonth()] or error("getMonth(): bad index?")
163+
end
164+
165+
function DateTime:toDuration()
166+
return Duration{ year = self.year, year_tick = self.year_tick }
167+
end
168+
169+
function DateTime:__add(other)
170+
if DEBUG then self:_debugOps(other) end
171+
-- normalize() handles adjustments to year and year_tick
172+
return DateTime{ year = (self.year + other.year), year_tick = (self.year_tick + other.year_tick) }
173+
end
174+
175+
-- might make sense to return a Duration here
176+
function DateTime:__sub(other)
177+
if DEBUG then self:_debugOps(other) end
178+
-- normalize() handles adjustments to year and year_tick
179+
return DateTime{ year = (self.year - other.year) , year_tick = (self.year_tick - other.year_tick) }
180+
end
181+
182+
-- Static functions
183+
function DateTime.now()
184+
return DateTime{ year = df.global.cur_year, year_tick = df.global.cur_year_tick }
185+
end
186+
187+
-- Ordinal suffix rules found here: https://en.wikipedia.org/wiki/Ordinal_indicator
188+
function DateTime.getOrdinalSuffix(ordinal)
189+
if (ordinal < 0) then
190+
ordinal = math.abs(ordinal)
191+
end
192+
193+
local rem = (ordinal < 100) and (ordinal % 10) or (ordinal % 100)
194+
-- rem can be between 11 and 13 only when ordinal is > 100
195+
if (ordinal >= 11 and ordinal <= 13) or (rem >= 11 and rem <= 13) then
196+
return 'th'
197+
end
198+
-- modulo again to handle the case when ordinal is > 100
199+
return ({'st', 'nd', 'rd'})[rem % 10] or 'th'
200+
end
201+
202+
Duration = defclass(Duration, DwarfCalendar)
203+
204+
-- returns ticks since year zero
205+
function Duration:getTicks()
206+
return self.year * TICKS_PER_YEAR + self.year_tick
207+
end
208+
209+
-- returns an integer pair: (days since year zero), (day tick count)
210+
function Duration:getDays()
211+
return self.year * DAYS_PER_YEAR + self:ticksToDays(), self:getDayTicks()
212+
end
213+
214+
-- returns an integer pair: (months since year zero), (month tick count)
215+
function Duration:getMonths()
216+
return self.year * MONTHS_PER_YEAR + self:ticksToMonths(), self:getMonthTicks()
217+
end
218+
219+
-- returns parts of an elapsed time:
220+
-- years,
221+
-- months, - since start of year
222+
-- days, - since start of month
223+
-- day tick count - since start of day
224+
function Duration:getYearsMonthsDays()
225+
return self.year, self:ticksToMonths(), self:ticksToDayOfMonth(), self:getDayTicks()
226+
end
227+
228+
function Duration:__add(other)
229+
if DEBUG then self:_debugOps(other) end
230+
-- normalize() handles adjustments to year and year_tick
231+
return Duration{ year = (self.year + other.year), year_tick = (self.year_tick + other.year_tick) }
232+
end
233+
234+
function Duration:__sub(other)
235+
if DEBUG then self:_debugOps(other) end
236+
-- normalize() handles adjustments to year and year_tick
237+
return Duration{ year = (self.year - other.year) , year_tick = (self.year_tick - other.year_tick) }
238+
end
239+
240+
return _ENV

0 commit comments

Comments
 (0)