1946055e创建于 2025年8月9日历史提交
/*
Copyright (c) 2025 WuJingrun(吴京润)

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
 */
package f_time

import std.convert.Parsable

public type TU = TimeUnit

public enum TimeUnit <: ToString & Parsable<TimeUnit> {
    | NANOSECOND
    | MICROSECOND
    | MILLISECOND
    | SECOND
    | MINUTE
    | HOUR
    | DAY
    | WEEK
    | MONTH
    | YEAR

    public static func parse(value: String): TimeUnit {
        tryParse(value).getOrThrow {IllegalArgumentException('${value} cannot be parsed to TimeUnit')}
    }
    public static func tryParse(value: String): Option<TimeUnit> {
        match (value.toAsciiUpper()) {
            case "NANOSECOND" => Some(NANOSECOND)
            case "MICROSECOND" => Some(MICROSECOND)
            case "MILLISECOND" => Some(MILLISECOND)
            case "SECOND" => Some(SECOND)
            case "MINUTE" => Some(MINUTE)
            case "HOUR" => Some(HOUR)
            case "DAY" => Some(DAY)
            case "WEEK" => Some(WEEK)
            case "MONTH" => Some(MONTH)
            case "YEAR" => Some(YEAR)
            case _ => None<TimeUnit>
        }
    }
    public prop current: DateTime {
        get() {
            trim(DateTime.now())
        }
    }
    /**
     * datetime在当前时间单位的未来duration个整点,duration可以是负数
     * 比如datetime是2023-10-11 12:31:32.568900,当前时间单位是minute,duration是1,返回值是2023-10-11 12:32:00.000000
     */
    public func next(datetime!: DateTime = DateTime.now(), duration!: Int64 = 1, toTrim!: Bool = true): DateTime {
        let d = if (toTrim) {
            trim(datetime)
        } else {
            datetime
        }
        match (this) {
            case NANOSECOND => d.addNanoseconds(duration)
            case MICROSECOND => d.addMicroseconds(duration)
            case MILLISECOND => d.addMilliseconds(duration)
            case SECOND => d.addSeconds(duration)
            case MINUTE => d.addMinutes(duration)
            case HOUR => d.addHours(duration)
            case DAY => d.addDays(duration)
            case WEEK => d.addWeeks(duration)
            case MONTH => d.addMonths(duration)
            case YEAR => d.addYears(duration)
        }
    }
    /**
     * datetime在当前时间单位的过去duration个整点,duration可以是负数
     * 比如datetime是2023-10-11 12:31:32.568900,当前时间单位是minute,duration是1,返回值是2023-10-11 12:31:00.000000
     */
    public func prev(datetime!: DateTime = DateTime.now(), duration!: Int64 = 1, toTrim!: Bool = true): DateTime {
        next(datetime: datetime, duration: -duration, toTrim: toTrim)
    }
    /**
     * datetime在当前时间单位距离未来duration个时间单位的时间长度,duration可以是负数
     * 比如datetime是2023-10-11 12:31:32.568900,当前时间单位是minute,返回值等于Duration.minute
     */
    public func since(datetime!: DateTime = DateTime.now(), duration!: Int64 = 1): Duration {
        next(datetime: datetime, duration: duration) - datetime
    }
    public func trim(t: DateTime): DateTime {
        match (this) {
            case NANOSECOND => t
            case MICROSECOND =>
                let year = t.year
                let month = t.month
                let day = t.dayOfMonth
                let hour = t.hour
                let min = t.minute
                let sec = t.second
                let nano = (t.nanosecond / 1000) * 1000
                DateTime.of(year: year, month: month, dayOfMonth: day, hour: hour, minute: min, second: sec,
                    nanosecond: nano)
            case MILLISECOND =>
                let year = t.year
                let month = t.month
                let day = t.dayOfMonth
                let hour = t.hour
                let min = t.minute
                let sec = t.second
                let nano = (t.nanosecond / 1000000) * 1000000
                DateTime.of(year: year, month: month, dayOfMonth: day, hour: hour, minute: min, second: sec,
                    nanosecond: nano)
            case SECOND =>
                let year = t.year
                let month = t.month
                let day = t.dayOfMonth
                let hour = t.hour
                let min = t.minute
                let sec = t.second
                let nano = 0
                DateTime.of(year: year, month: month, dayOfMonth: day, hour: hour, minute: min, second: sec,
                    nanosecond: nano)
            case MINUTE =>
                let year = t.year
                let month = t.month
                let day = t.dayOfMonth
                let hour = t.hour
                let min = t.minute
                let sec = 0
                let nano = 0
                DateTime.of(year: year, month: month, dayOfMonth: day, hour: hour, minute: min, second: sec,
                    nanosecond: nano)
            case HOUR =>
                let year = t.year
                let month = t.month
                let day = t.dayOfMonth
                let hour = t.hour
                let min = 0
                let sec = 0
                let nano = 0
                DateTime.of(year: year, month: month, dayOfMonth: day, hour: hour, minute: min, second: sec,
                    nanosecond: nano)
            case DAY =>
                let year = t.year
                let month = t.month
                let day = t.dayOfMonth
                let hour = 0
                let min = 0
                let sec = 0
                let nano = 0
                DateTime.of(year: year, month: month, dayOfMonth: day, hour: hour, minute: min, second: sec,
                    nanosecond: nano)
            case MONTH =>
                let year = t.year
                let month = t.month
                let day = 1
                let hour = 0
                let min = 0
                let sec = 0
                let nano = 0
                DateTime.of(year: year, month: month, dayOfMonth: day, hour: hour, minute: min, second: sec,
                    nanosecond: nano)
            case YEAR =>
                let year = t.year
                let month = Month.January
                let day = 1
                let hour = 0
                let min = 0
                let sec = 0
                let nano = 0
                DateTime.of(year: year, month: month, dayOfMonth: day, hour: hour, minute: min, second: sec,
                    nanosecond: nano)
            case WEEK =>
                let weekday = t.dayOfWeek.toInteger()
                let date = t.addDays(-weekday)
                let year = date.year
                let month = date.month
                let day = date.dayOfMonth
                let hour = 0
                let min = 0
                let sec = 0
                let nano = 0
                DateTime.of(year: year, month: month, dayOfMonth: day, hour: hour, minute: min, second: sec,
                    nanosecond: nano)
        }
    }
    public func ago(duration: Int64): DateTime {
        before(DateTime.now(), duration)
    }
    public func before(t: DateTime, duration: Int64) {
        after(t, -duration)
    }
    public func later(duration: Int64): DateTime {
        after(DateTime.now(), duration)
    }
    public func after(t: DateTime, duration: Int64): DateTime {
        match (this) {
            case YEAR => t.addYears(duration)
            case MONTH => t.addMonths(duration)
            case DAY => t.addDays(duration)
            case WEEK => t.addWeeks(duration)
            case HOUR => t.addHours(duration)
            case MINUTE => t.addMinutes(duration)
            case SECOND => t.addSeconds(duration)
            case MILLISECOND => t.addMilliseconds(duration)
            case MICROSECOND => t.addMicroseconds(duration)
            case NANOSECOND => t.addNanoseconds(duration)
        }
    }

    public func duration(n: Int64): Option<Duration> {
        match (this) {
            case NANOSECOND => n * Duration.nanosecond
            case MICROSECOND => n * Duration.microsecond
            case MILLISECOND => n * Duration.millisecond
            case SECOND => n * Duration.second
            case MINUTE => n * Duration.minute
            case HOUR => n * Duration.hour
            case DAY => n * Duration.day
            case _ => None<Duration>
        }
    }

    public func name(): String {
        toString()
    }
    public func toString(): String {
        match (this) {
            case NANOSECOND => "NANOSECOND"
            case MICROSECOND => "MICROSECOND"
            case MILLISECOND => "MILLISECOND"
            case SECOND => "SECOND"
            case MINUTE => "MINUTE"
            case HOUR => "HOUR"
            case DAY => "DAY"
            case WEEK => "WEEK"
            case MONTH => "MONTH"
            case YEAR => "YEAR"
        }
    }
}