///|
pub fn Duration::Duration(
negative? : Bool = false,
weeks? : Int = 0,
days? : Int = 0,
hours? : Int = 0,
minutes? : Int = 0,
seconds? : Int = 0,
) -> Duration {
Duration::{ negative, weeks, days, hours, minutes, seconds }
}
///|
pub fn Duration::is_zero(self : Duration) -> Bool {
self.weeks == 0 &&
self.days == 0 &&
self.hours == 0 &&
self.minutes == 0 &&
self.seconds == 0
}
///|
pub fn Duration::total_seconds(self : Duration) -> Int {
let value = self.weeks * 7 * 86400 +
self.days * 86400 +
self.hours * 3600 +
self.minutes * 60 +
self.seconds
if self.negative {
0 - value
} else {
value
}
}
///|
pub fn Duration::apply(self : Duration, start : DateTime) -> DateTime {
start.add_seconds(self.total_seconds())
}
///|
pub fn Duration::format(self : Duration) -> String {
let b = StringBuilder()
if self.negative {
b.write_string("-")
}
b.write_string("P")
if self.weeks != 0 {
b.write_string("\{self.weeks}W")
} else {
if self.days != 0 {
b.write_string("\{self.days}D")
}
if self.hours != 0 || self.minutes != 0 || self.seconds != 0 {
b.write_string("T")
if self.hours != 0 {
b.write_string("\{self.hours}H")
}
if self.minutes != 0 {
b.write_string("\{self.minutes}M")
}
if self.seconds != 0 {
b.write_string("\{self.seconds}S")
}
}
if self.days == 0 &&
self.hours == 0 &&
self.minutes == 0 &&
self.seconds == 0 {
b.write_string("T0S")
}
}
b.to_string()
}
///|
pub impl Show for Duration with fn to_string(self) {
self.format()
}
///|
pub fn parse_duration(input : String) -> Result[Duration, MoonCalError] {
let raw = input.trim().to_owned()
if raw.is_empty() {
return Err(
InvalidProperty(line=0, name="DURATION", message="duration is empty"),
)
}
let negative = raw.has_prefix("-")
let positive = if negative {
raw[1:].to_owned()
} else if raw.has_prefix("+") {
raw[1:].to_owned()
} else {
raw
}
if !positive.has_prefix("P") || positive.length() < 2 {
return Err(
InvalidProperty(
line=0,
name="DURATION",
message="duration must start with P",
),
)
}
let mut weeks = 0
let mut days = 0
let mut hours = 0
let mut minutes = 0
let mut seconds = 0
let mut in_time = false
let mut number = ""
let mut saw_component = false
for i in 1.. {
if in_time || !number.is_empty() {
return Err(
InvalidProperty(line=0, name="DURATION", message="bad T marker"),
)
}
in_time = true
}
Some(c) if c >= '0' && c <= '9' => number = number + c.to_string()
Some('W') => {
if in_time || saw_component || number.is_empty() {
return Err(
InvalidProperty(
line=0,
name="DURATION",
message="W must be the only date component",
),
)
}
weeks = match parse_positive_int(number) {
Some(n) => n
None =>
return Err(
InvalidProperty(line=0, name="DURATION", message="bad week value"),
)
}
number = ""
saw_component = true
}
Some('D') => {
if in_time || number.is_empty() {
return Err(
InvalidProperty(
line=0,
name="DURATION",
message="bad day component",
),
)
}
days = match parse_positive_int(number) {
Some(n) => n
None =>
return Err(
InvalidProperty(line=0, name="DURATION", message="bad day value"),
)
}
number = ""
saw_component = true
}
Some('H') => {
if !in_time || number.is_empty() {
return Err(
InvalidProperty(
line=0,
name="DURATION",
message="bad hour component",
),
)
}
hours = match parse_positive_int(number) {
Some(n) => n
None =>
return Err(
InvalidProperty(line=0, name="DURATION", message="bad hour value"),
)
}
number = ""
saw_component = true
}
Some('M') => {
if !in_time || number.is_empty() {
return Err(
InvalidProperty(
line=0,
name="DURATION",
message="bad minute component",
),
)
}
minutes = match parse_positive_int(number) {
Some(n) => n
None =>
return Err(
InvalidProperty(
line=0,
name="DURATION",
message="bad minute value",
),
)
}
number = ""
saw_component = true
}
Some('S') => {
if !in_time || number.is_empty() {
return Err(
InvalidProperty(
line=0,
name="DURATION",
message="bad second component",
),
)
}
seconds = match parse_positive_int(number) {
Some(n) => n
None =>
return Err(
InvalidProperty(
line=0,
name="DURATION",
message="bad second value",
),
)
}
number = ""
saw_component = true
}
_ =>
return Err(
InvalidProperty(
line=0,
name="DURATION",
message="unexpected character",
),
)
}
}
if !number.is_empty() || !saw_component {
return Err(
InvalidProperty(
line=0,
name="DURATION",
message="duration has trailing number or no component",
),
)
}
let duration = Duration(negative~, weeks~, days~, hours~, minutes~, seconds~)
Ok(duration)
}