time module
This commit is contained in:
parent
ed41828ecb
commit
0f984696c7
1 changed files with 325 additions and 0 deletions
325
Luxe/math/time.wren
Normal file
325
Luxe/math/time.wren
Normal file
|
|
@ -0,0 +1,325 @@
|
|||
import "luxe: io" for IO
|
||||
|
||||
//modulo utility function in here to make this pretty self contained for now
|
||||
var mod = Fn.new{|dividend, divisor|
|
||||
return (dividend%divisor + divisor) % divisor
|
||||
}
|
||||
|
||||
//time based on epoch time - assumes time is after 1.1.1970 and doesnt do leap seconds
|
||||
class DateTime{
|
||||
static seconds_per_minute{60}
|
||||
static seconds_per_hour{3600}
|
||||
static seconds_per_day{86400}
|
||||
static minutes_per_hour{60}
|
||||
static hours_per_day{24}
|
||||
static epoch{1970}
|
||||
|
||||
toString{
|
||||
var month_names = ["jan", "feb", "mar", "apr", "may", "jun", "jul", "aug", "sep", "oct", "nov", "dec"]
|
||||
var week_names = ["mon", "tue", "wed", "thu", "fri", "sat", "sun"]
|
||||
var ends = ["th", "st", "nd", "rd", "th", "th", "th", "th", "th", "th"]
|
||||
return "%(week_names[day_of_week]), %(days+1)%(ends[(days+1)%10]) of %(month_names[months]) %(years) "+
|
||||
"%(hours):%(minutes):%(seconds)"
|
||||
}
|
||||
|
||||
total_seconds{_time}
|
||||
total_minutes{(_time / DateTime.seconds_per_minute).truncate}
|
||||
total_hours{(_time / DateTime.seconds_per_hour).truncate}
|
||||
total_days{(_time / DateTime.seconds_per_day).truncate}
|
||||
total_years{years}
|
||||
|
||||
seconds{total_seconds % DateTime.seconds_per_minute}
|
||||
minutes{(total_minutes % DateTime.minutes_per_hour).truncate}
|
||||
hours{(total_hours % DateTime.hours_per_day).truncate}
|
||||
days{
|
||||
var months = [31, DateTime.is_leap_year(years)?29:28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
|
||||
var month = 0
|
||||
var days = day_in_year
|
||||
while(days >= months[month]){
|
||||
days = days - months[month]
|
||||
month = month + 1
|
||||
}
|
||||
return days
|
||||
}
|
||||
day_in_year{
|
||||
var days = total_days
|
||||
var year = DateTime.epoch
|
||||
//while the day is in a later year
|
||||
while(days >= 365){
|
||||
if(DateTime.is_leap_year(year)){
|
||||
if(days == 365) return days
|
||||
days = days - 366
|
||||
} else {
|
||||
days = days - 365
|
||||
}
|
||||
year = year + 1
|
||||
}
|
||||
return days
|
||||
}
|
||||
//day of the week from monday=0 to sunday=6
|
||||
day_of_week{
|
||||
return (total_days + 3) % 7 //+3 is because 1.1.1970 was a thursday
|
||||
}
|
||||
week_in_year{
|
||||
//what
|
||||
return ((day_in_year-day_of_week-1)/7).truncate+1
|
||||
}
|
||||
months{
|
||||
var months = [31, DateTime.is_leap_year(years)?29:28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
|
||||
var month = 0
|
||||
var days = day_in_year
|
||||
while(days >= months[month]){
|
||||
days = days - months[month]
|
||||
month = month + 1
|
||||
}
|
||||
return month
|
||||
}
|
||||
years{
|
||||
return DateTime.epoch + ((total_days - leap_days_since_epoch_start) / 365).truncate
|
||||
}
|
||||
leap_days_since_epoch_start{
|
||||
var days = total_days
|
||||
var year = DateTime.epoch
|
||||
var leaps = 0
|
||||
//while the day is in a later year or later than january 29/march 1
|
||||
while(days > 58){
|
||||
if(DateTime.is_leap_year(year)){
|
||||
leaps = leaps + 1
|
||||
days = days - 366
|
||||
} else {
|
||||
days = days - 365
|
||||
}
|
||||
year = year + 1
|
||||
}
|
||||
return leaps
|
||||
}
|
||||
|
||||
is_leap_year{is_leap_year(years)}
|
||||
|
||||
static is_leap_year(year){
|
||||
return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)
|
||||
}
|
||||
|
||||
construct new(epoch){
|
||||
_time = epoch
|
||||
}
|
||||
|
||||
construct now(){
|
||||
_time = IO.time_since_epoch_utc()
|
||||
}
|
||||
|
||||
construct clone(instance){
|
||||
_time = instance.total_seconds
|
||||
}
|
||||
|
||||
//overloads
|
||||
static from_time(years) {from_time(years, 0, 0, 0, 0, 0)}
|
||||
static from_time(years, months) {from_time(years, months, 0, 0, 0, 0)}
|
||||
static from_time(years, months, days) {from_time(years, months, days, 0, 0, 0)}
|
||||
static from_time(years, months, days, hours) {from_time(years, months, days, hours, 0, 0)}
|
||||
static from_time(years, months, days, hours, minutes) {from_time(years, months, days, hours, minutes, 0)}
|
||||
|
||||
construct from_time(years, months, days, hours, minutes, seconds){
|
||||
if(years < DateTime.epoch) {
|
||||
System.print("[warn] dates before %(DateTime.epoch) aren't possible yet :(")
|
||||
return
|
||||
}
|
||||
for(i in DateTime.epoch...years){
|
||||
days = days + (DateTime.is_leap_year(i)?366:365)
|
||||
}
|
||||
var month_days = [31, DateTime.is_leap_year(years)?29:28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
|
||||
for(i in 0...months){
|
||||
days = days + month_days[i]
|
||||
}
|
||||
_time = days * DateTime.seconds_per_day + hours * DateTime.seconds_per_hour + minutes * DateTime.seconds_per_minute + seconds
|
||||
}
|
||||
|
||||
add_seconds(second_diff){
|
||||
_time = _time + second_diff
|
||||
}
|
||||
|
||||
add_minutes(minute_diff){
|
||||
_time = _time + minute_diff * DateTime.seconds_per_minute
|
||||
}
|
||||
|
||||
add_hours(hour_diff){
|
||||
_time = _time + hour_diff * DateTime.seconds_per_hour
|
||||
}
|
||||
|
||||
add_days(day_diff){
|
||||
_time = _time + day_diff * DateTime.seconds_per_day
|
||||
}
|
||||
|
||||
add_weeks(week_diff){
|
||||
_time = _time + week_diff * DateTime.seconds_per_day * 7
|
||||
}
|
||||
|
||||
add_months(month_diff){
|
||||
var month_days = [31, null, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
|
||||
var day_difference = 0
|
||||
var month = months
|
||||
var year = years
|
||||
var sign = month_diff.sign
|
||||
var original_days = days
|
||||
//execute once if counting down to use the next months days, not this months days
|
||||
if(sign < 0){
|
||||
month = month + sign
|
||||
if(month < 0){
|
||||
month = month + 12
|
||||
year = year - 1
|
||||
}
|
||||
if(month >= 12){
|
||||
month = month - 12
|
||||
year = year + 1
|
||||
}
|
||||
}
|
||||
//collect days we have to move the time
|
||||
for(i in 0...month_diff){
|
||||
var days = month_days[month]
|
||||
if(days){
|
||||
day_difference = day_difference + days * sign
|
||||
} else {
|
||||
day_difference = day_difference + (DateTime.is_leap_year(year)?29:28) * sign
|
||||
}
|
||||
month = month + sign
|
||||
if(month < 0){
|
||||
month = month + 12
|
||||
year = year - 1
|
||||
}
|
||||
if(month >= 12){
|
||||
month = month - 12
|
||||
year = year + 1
|
||||
}
|
||||
}
|
||||
add_days(day_difference)
|
||||
//if the days shifted we can assume we jumped, for example from a 31st of jan to a 2nd of march since the feb is short
|
||||
//so we just go back until we arrive in the previous month
|
||||
var new_days = days
|
||||
if(new_days != original_days){
|
||||
add_days(-new_days-1)
|
||||
}
|
||||
}
|
||||
|
||||
add_years(year_diff){
|
||||
var before_leap = day_in_year <= 59
|
||||
var day_difference = 0
|
||||
var year = years
|
||||
var sign = year_diff.sign
|
||||
if(sign > 0 != before_leap){
|
||||
year = year + sign
|
||||
}
|
||||
for(i in 0...year_diff){
|
||||
day_difference = day_difference + sign * (DateTime.is_leap_year(year)?366:365)
|
||||
year = year + sign
|
||||
}
|
||||
add_days(day_difference)
|
||||
}
|
||||
|
||||
add(span){
|
||||
_time = _time + span.total_seconds
|
||||
}
|
||||
|
||||
set(time){
|
||||
_time = time
|
||||
}
|
||||
|
||||
update(){
|
||||
_time = IO.time_since_epoch_utc()
|
||||
}
|
||||
|
||||
static difference(time_1, time_2){
|
||||
return TimeSpan.new((time_1.total_seconds - time_2.total_seconds).abs)
|
||||
}
|
||||
|
||||
+(val){
|
||||
if(val is TimeSpan){
|
||||
return DateTime.new(_time + val.total_seconds)
|
||||
}
|
||||
Fiber.abort("Can't add DateTime and %(val.type.name)")
|
||||
}
|
||||
|
||||
-(val){
|
||||
if(val is DateTime){
|
||||
return DateTime.difference(this, val)
|
||||
}
|
||||
if(val is TimeSpan){
|
||||
return DateTime.new(_time - val.total_seconds)
|
||||
}
|
||||
Fiber.abort("Can't subtract %(val.type.name) from TimeSpan")
|
||||
}
|
||||
}
|
||||
|
||||
class TimeSpan{
|
||||
static zero{TimeSpan.new(0)}
|
||||
|
||||
toString{"%(days) days, %(hours) hours, %(minutes) minutes, and %(seconds) seconds"}
|
||||
|
||||
total_seconds{_time}
|
||||
total_minutes{(_time / DateTime.seconds_per_minute).truncate}
|
||||
total_hours{(_time / DateTime.seconds_per_hour).truncate}
|
||||
total_days{(_time / DateTime.seconds_per_day).truncate}
|
||||
|
||||
seconds{total_seconds % DateTime.seconds_per_minute}
|
||||
minutes{total_minutes % DateTime.minutes_per_hour}
|
||||
hours{total_hours % DateTime.hours_per_day}
|
||||
days{total_days}
|
||||
//months and years are not possible because we don't know which months/years we're talking about
|
||||
|
||||
construct new(time){
|
||||
_time = time
|
||||
}
|
||||
|
||||
construct from_seconds(seconds){
|
||||
_time = seconds
|
||||
}
|
||||
|
||||
construct from_minutes(minutes){
|
||||
_time = minutes * DateTime.seconds_per_minute
|
||||
}
|
||||
|
||||
construct from_hours(hours){
|
||||
_time = hours * DateTime.seconds_per_hour
|
||||
}
|
||||
|
||||
construct from_days(days){
|
||||
_time = days * DateTime.seconds_per_day
|
||||
}
|
||||
|
||||
add_seconds(seconds){
|
||||
_time = _time + seconds
|
||||
}
|
||||
|
||||
add_minutes(minutes){
|
||||
_time = _time + minutes * DateTime.seconds_per_minute
|
||||
}
|
||||
|
||||
add_hours(hours){
|
||||
_time = _time + hours * DateTime.seconds_per_hour
|
||||
}
|
||||
|
||||
add_days(days){
|
||||
_time = _time + days * DateTime.seconds_per_day
|
||||
}
|
||||
|
||||
add(span){
|
||||
_time = _time + span.total_seconds
|
||||
}
|
||||
|
||||
set(time){
|
||||
_time = time
|
||||
}
|
||||
|
||||
+(val){
|
||||
if(val is TimeSpan){
|
||||
return TimeSpan.new(_time + val.total_seconds)
|
||||
}
|
||||
Fiber.abort("Can't add TimeSpan and %(val.type.name)")
|
||||
}
|
||||
|
||||
-(val){
|
||||
if(val is TimeSpan){
|
||||
return TimeSpan.new(_time - val.total_seconds)
|
||||
}
|
||||
Fiber.abort("Can't add TimeSpan and %(val.type.name)")
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue