• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

moonbitlang / x / 301

10 Dec 2024 06:19AM UTC coverage: 85.204% (-2.6%) from 87.841%
301

Pull #78

github

web-flow
Merge b830031f4 into 91f0fdf48
Pull Request #78: feat: new package encoding

105 of 161 new or added lines in 3 files covered. (65.22%)

124 existing lines in 29 files now uncovered.

1169 of 1372 relevant lines covered (85.2%)

434.92 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

93.94
/time/duration.mbt
1
// Copyright 2024 International Digital Economy Academy
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
//     http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14

15
///| An amount of time with nanosecond precision.
16
struct Duration {
17
  secs : Int64
18
  nanos : Int
19
} derive(Eq, Compare)
20

21
///| Creates a Duration from hours, minutes, seconds and nanoseconds.
22
pub fn Duration::of(
23
  hours~ : Int64 = 0L,
24
  minutes~ : Int64 = 0L,
25
  seconds~ : Int64 = 0L,
26
  nanoseconds~ : Int64 = 0L
27
) -> Duration!Error {
28
  let hours_sec = checked_mul_int64!(hours, seconds_per_hour)
49✔
29
  let minutes_sec = checked_mul_int64!(minutes, seconds_per_minute)
49✔
30
  let mut secs = checked_add_int64!(
49✔
31
    checked_add_int64!(hours_sec, minutes_sec),
49✔
32
    seconds,
33
  )
34
  let nanos = (nanoseconds % nanoseconds_per_second).to_int()
49✔
35
  secs += nanoseconds / nanoseconds_per_second
36
  { secs, nanos }
37
}
38

39
///|
40
fn create(secs : Int64, nanos : Int) -> Duration!Error {
41
  if nanos < min_nanosecond || nanos > max_nanosecond {
5✔
UNCOV
42
    fail!(invalid_duration_err)
×
43
  }
44
  { secs, nanos }
45
}
46

47
///| Returns a zero length duration.
48
pub fn Duration::zero() -> Duration {
49
  { secs: 0L, nanos: 0 }
35✔
50
}
51

52
///| Parses a ISO 8601 format string like `PT[n]H[n]M[n].[n]S`.
53
pub fn Duration::from_string(str : String) -> Duration!Error {
54
  // TODO: better parsing impl
55
  if str.substring(end=2) != "PT" {
6✔
UNCOV
56
    fail!(invalid_duration_err)
×
57
  }
58
  let mut hours = 0L
59
  let mut minutes = 0L
60
  let mut seconds = 0L
61
  let mut nanoseconds = 0L
62
  let buf = StringBuilder::new(size_hint=0)
63
  for i = 2; i < str.length(); i = i + 1 {
40✔
64
    match str[i] {
45✔
65
      '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' | '.' | '-' =>
66
        buf.write_char(str[i])
36✔
67
      'H' => {
2✔
68
        hours = @strconv.parse!(buf.to_string())
69
        buf.reset()
2✔
70
      }
71
      'M' => {
2✔
72
        minutes = @strconv.parse!(buf.to_string())
73
        buf.reset()
2✔
74
      }
75
      'S' => {
5✔
76
        let s = buf.to_string()
77
        let splits = split(s, '.')
78
        if splits.is_empty() || splits.length() > 2 {
UNCOV
79
          fail!(invalid_duration_err)
×
80
        }
81
        if splits.length() > 0 && splits[0] != "" {
82
          let secs_str = splits[0]
4✔
83
          seconds = @strconv.parse!(secs_str)
4✔
84
        }
85
        if splits.length() > 1 && splits[1] != "" {
86
          let mut nanos_str = splits[1]
3✔
87
          nanos_str = add_suffix_zero(nanos_str, 9)
88
          if seconds < 0L {
89
            nanos_str = "-" + nanos_str
1✔
90
          }
91
          nanoseconds = @strconv.parse!(nanos_str)
3✔
92
        }
93
        break
94
      }
UNCOV
95
      _ => fail!(invalid_duration_err)
×
96
    }
97
  }
98
  Duration::of!(hours~, minutes~, seconds~, nanoseconds~)
4✔
99
}
100

101
///| Returns a string representation of this duration using ISO 8601 representation.
102
pub fn to_string(self : Duration) -> String {
103
  if self.is_zero() {
46✔
104
    return "PT0S"
6✔
105
  }
106
  let buf = StringBuilder::new(size_hint=0)
107
  buf.write_string("PT")
108
  let total_secs = self.secs
109
  let hours = total_secs / seconds_per_hour
110
  let minutes = total_secs % seconds_per_hour / seconds_per_minute
111
  let seconds = total_secs % seconds_per_minute
112
  let nanos_of_seconds = seconds * nanoseconds_per_second +
113
    self.nanos.to_int64()
114
  let secs = (nanos_of_seconds / nanoseconds_per_second).abs()
115
  let nanos = (nanos_of_seconds % nanoseconds_per_second).abs()
116
  if hours != 0L {
117
    buf.write_string(hours.to_string())
20✔
118
    buf.write_char('H')
119
  }
120
  if minutes != 0L {
121
    buf.write_string(minutes.to_string())
18✔
122
    buf.write_char('M')
123
  }
124
  if secs != 0L || nanos > 0L {
125
    if nanos_of_seconds < 0L {
28✔
126
      buf.write_char('-')
13✔
127
    }
128
    buf.write_string(secs.to_string())
129
    if nanos > 0L {
130
      buf.write_char('.')
20✔
131
      let nanos_str = (nanos + nanoseconds_per_second)
132
        .to_string()
133
        .substring(start=1)
134
      buf.write_string(remove_suffix_zero(nanos_str))
135
    }
136
    buf.write_char('S')
137
  }
138
  buf.to_string()
139
}
140

141
///|
142
pub impl Show for Duration with output(self : Duration, logger : Logger) -> Unit {
143
  logger.write_string(self.to_string())
46✔
144
}
145

146
///| Returns the number of seconds in this duration.
147
pub fn seconds(self : Duration) -> Int64 {
148
  self.secs
1✔
149
}
150

151
///| Returns the number of nanoseconds in this duration.
152
pub fn nanoseconds(self : Duration) -> Int {
153
  self.nanos
1✔
154
}
155

156
///| Checks if this duration is zero length.
157
pub fn is_zero(self : Duration) -> Bool {
158
  self.secs == 0L && self.nanos == 0
67✔
159
}
160

161
///| Checks if this duration is negative.
162
pub fn is_neg(self : Duration) -> Bool {
163
  self.secs < 0L
5✔
164
}
165

166
///| Adds specified hours to this duration, and returns a new duration.
167
pub fn add_hours(self : Duration, hours : Int64) -> Duration!Error {
168
  if hours == 0L {
7✔
169
    return self
1✔
170
  }
171
  let secs = checked_add_int64!(
172
    self.secs,
173
    checked_mul_int64!(hours, seconds_per_hour),
4✔
174
  )
175
  { ..self, secs, }
4✔
176
}
177

178
///| Adds specified minutes to this duration, and returns a new duration.
179
pub fn add_minutes(self : Duration, minutes : Int64) -> Duration!Error {
180
  if minutes == 0L {
7✔
181
    return self
1✔
182
  }
183
  let secs = checked_add_int64!(
184
    self.secs,
185
    checked_mul_int64!(minutes, seconds_per_minute),
4✔
186
  )
187
  { ..self, secs, }
4✔
188
}
189

190
///| Adds specified seconds to this duration, and returns a new duration.
191
pub fn add_seconds(self : Duration, seconds : Int64) -> Duration!Error {
192
  if seconds == 0L {
7✔
193
    return self
1✔
194
  }
195
  let secs = checked_add_int64!(self.secs, seconds)
196
  { ..self, secs, }
4✔
197
}
198

199
///| Adds specified nanoseconds to this duration, and returns a new duration.
200
pub fn add_nanoseconds(self : Duration, nanoseconds : Int64) -> Duration!Error {
201
  if nanoseconds == 0L {
13✔
202
    return self
1✔
203
  }
204
  let seconds = checked_add_int64!(
205
    self.secs,
206
    nanoseconds / nanoseconds_per_second,
207
  )
208
  let nanoseconds = nanoseconds % nanoseconds_per_second
10✔
209
  Duration::of!(seconds~, nanoseconds~)
10✔
210
}
211

212
///| Adds other duration to this duration, and returns a new duration.
213
pub fn add_duration(self : Duration, other : Duration) -> Duration!Error {
214
  if other.is_zero() {
6✔
215
    return self
1✔
216
  }
217
  let mut nanos = self.nanos.to_int64() + other.nanos.to_int64()
218
  let mut secs = checked_add_int64!(self.secs, other.secs)
219
  secs = checked_add_int64!(secs, nanos / nanoseconds_per_second)
3✔
220
  nanos = nanos % nanoseconds_per_second
3✔
221
  if nanos < 0L {
222
    secs -= 1L
1✔
223
    nanos += nanoseconds_per_second
224
  }
225
  create!(secs, nanos.to_int())
3✔
226
}
227

228
///|
229
pub fn op_add(self : Duration, other : Duration) -> Duration!Error {
230
  self.add_duration!(other)
4✔
231
}
232

233
///| Returns a new duration with the specified amount of seconds.
234
pub fn with_seconds(self : Duration, seconds : Int64) -> Duration {
235
  if seconds == self.secs {
2✔
236
    return self
1✔
237
  }
238
  { secs: seconds, nanos: self.nanos }
239
}
240

241
///| Returns a new duration with the specified nanosecond of second.
242
pub fn with_nanoseconds(self : Duration, nanoseconds : Int) -> Duration!Error {
243
  if nanoseconds == self.nanos {
3✔
244
    return self
1✔
245
  }
246
  create!(self.secs, nanoseconds)
1✔
247
}
248

249
///| Converts this duration to the total length in nanoseconds.
250
pub fn to_nanoseconds(self : Duration) -> Int64 {
251
  self.secs * nanoseconds_per_second + self.nanos.to_int64()
2✔
252
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc