325 lines
No EOL
8.8 KiB
Text
325 lines
No EOL
8.8 KiB
Text
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)")
|
|
}
|
|
} |