Files
herolib/lib/servers/calendar/calbox/duration.v
2025-02-17 06:40:06 +03:00

168 lines
3.6 KiB
V

module calbox
// Represents a duration in seconds
pub struct Duration {
pub:
seconds i64
}
// Parses an ISO 8601 duration string (e.g. PT1H30M)
pub fn parse_duration(iso_duration string) !Duration {
if iso_duration.len < 2 || !iso_duration.starts_with('P') {
return error('Invalid duration format: must start with P')
}
mut seconds := i64(0)
mut number_str := ''
mut time_part := false
for i := 1; i < iso_duration.len; i++ {
c := iso_duration[i]
match c {
`T` {
if time_part {
return error('Invalid duration format: duplicate T')
}
time_part = true
}
`0`...`9` {
number_str += c.ascii_str()
}
`Y` {
if time_part {
return error('Invalid duration format: Y in time part')
}
if number_str == '' {
return error('Invalid duration format: missing number before Y')
}
years := number_str.i64()
seconds += years * 365 * 24 * 60 * 60 // Approximate
number_str = ''
}
`M` {
if number_str == '' {
return error('Invalid duration format: missing number before M')
}
if time_part {
// Minutes
minutes := number_str.i64()
seconds += minutes * 60
} else {
// Months
months := number_str.i64()
seconds += months * 30 * 24 * 60 * 60 // Approximate
}
number_str = ''
}
`W` {
if time_part {
return error('Invalid duration format: W in time part')
}
if number_str == '' {
return error('Invalid duration format: missing number before W')
}
weeks := number_str.i64()
seconds += weeks * 7 * 24 * 60 * 60
number_str = ''
}
`D` {
if time_part {
return error('Invalid duration format: D in time part')
}
if number_str == '' {
return error('Invalid duration format: missing number before D')
}
days := number_str.i64()
seconds += days * 24 * 60 * 60
number_str = ''
}
`H` {
if !time_part {
return error('Invalid duration format: H in date part')
}
if number_str == '' {
return error('Invalid duration format: missing number before H')
}
hours := number_str.i64()
seconds += hours * 60 * 60
number_str = ''
}
`S` {
if !time_part {
return error('Invalid duration format: S in date part')
}
if number_str == '' {
return error('Invalid duration format: missing number before S')
}
seconds += number_str.i64()
number_str = ''
}
else {
return error('Invalid duration format: unknown character ${c}')
}
}
}
if number_str != '' {
return error('Invalid duration format: number without unit')
}
return Duration{seconds}
}
// Formats the duration as an ISO 8601 duration string
pub fn (d Duration) str() string {
mut s := 'P'
mut remaining := d.seconds
// Years (approximate)
years := remaining / (365 * 24 * 60 * 60)
if years > 0 {
s += '${years}Y'
remaining = remaining % (365 * 24 * 60 * 60)
}
// Days
days := remaining / (24 * 60 * 60)
if days > 0 {
s += '${days}D'
remaining = remaining % (24 * 60 * 60)
}
// Time part (hours, minutes, seconds)
if remaining > 0 {
s += 'T'
// Hours
hours := remaining / (60 * 60)
if hours > 0 {
s += '${hours}H'
remaining = remaining % (60 * 60)
}
// Minutes
minutes := remaining / 60
if minutes > 0 {
s += '${minutes}M'
remaining = remaining % 60
}
// Seconds
if remaining > 0 {
s += '${remaining}S'
}
}
return s
}
// Adds the duration to a timestamp
pub fn (d Duration) add_to(timestamp i64) i64 {
return timestamp + d.seconds
}
// Subtracts the duration from a timestamp
pub fn (d Duration) subtract_from(timestamp i64) i64 {
return timestamp - d.seconds
}