Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in
Toggle navigation
G
golang
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Commits
Issue Boards
Open sidebar
go
golang
Commits
f298d0ce
Commit
f298d0ce
authored
Dec 23, 2011
by
David Symonds
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
time: add ParseDuration.
R=rsc, r, r CC=golang-dev
https://golang.org/cl/5489111
parent
e6a322b0
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
207 additions
and
16 deletions
+207
-16
format.go
src/pkg/time/format.go
+130
-16
time_test.go
src/pkg/time/time_test.go
+77
-0
No files found.
src/pkg/time/format.go
View file @
f298d0ce
...
...
@@ -283,25 +283,16 @@ var atoiError = errors.New("time: invalid number")
// Duplicates functionality in strconv, but avoids dependency.
func
atoi
(
s
string
)
(
x
int
,
err
error
)
{
i
:=
0
if
len
(
s
)
>
0
&&
s
[
0
]
==
'-'
{
i
++
neg
:=
false
if
s
!=
""
&&
s
[
0
]
==
'-'
{
neg
=
true
s
=
s
[
1
:
]
}
if
i
>=
len
(
s
)
{
x
,
rem
,
err
:=
leadingInt
(
s
)
if
err
!=
nil
||
rem
!=
""
{
return
0
,
atoiError
}
for
;
i
<
len
(
s
);
i
++
{
c
:=
s
[
i
]
if
c
<
'0'
||
c
>
'9'
{
return
0
,
atoiError
}
if
x
>=
(
1
<<
31
-
10
)
/
10
{
// will overflow
return
0
,
atoiError
}
x
=
x
*
10
+
int
(
c
)
-
'0'
}
if
s
[
0
]
==
'-'
{
if
neg
{
x
=
-
x
}
return
x
,
nil
...
...
@@ -893,3 +884,126 @@ func parseNanoseconds(value string, nbytes int) (ns int, rangeErrString string,
}
return
}
var
errLeadingInt
=
errors
.
New
(
"time: bad [0-9]*"
)
// never printed
// leadingInt consumes the leading [0-9]* from s.
func
leadingInt
(
s
string
)
(
x
int
,
rem
string
,
err
error
)
{
i
:=
0
for
;
i
<
len
(
s
);
i
++
{
c
:=
s
[
i
]
if
c
<
'0'
||
c
>
'9'
{
break
}
if
x
>=
(
1
<<
31
-
10
)
/
10
{
// overflow
return
0
,
""
,
errLeadingInt
}
x
=
x
*
10
+
int
(
c
)
-
'0'
}
return
x
,
s
[
i
:
],
nil
}
var
unitMap
=
map
[
string
]
float64
{
"ns"
:
float64
(
Nanosecond
),
"us"
:
float64
(
Microsecond
),
"µs"
:
float64
(
Microsecond
),
// U+00B5 = micro symbol
"μs"
:
float64
(
Microsecond
),
// U+03BC = Greek letter mu
"ms"
:
float64
(
Millisecond
),
"s"
:
float64
(
Second
),
"m"
:
float64
(
Minute
),
"h"
:
float64
(
Hour
),
}
// ParseDuration parses a duration string.
// A duration string is a possibly signed sequence of
// decimal numbers, each with optional fraction and a unit suffix,
// such as "300ms", "-1.5h" or "2h45m".
// Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h".
func
ParseDuration
(
s
string
)
(
Duration
,
error
)
{
// [-+]?([0-9]*(\.[0-9]*)?[a-z]+)+
orig
:=
s
f
:=
float64
(
0
)
neg
:=
false
// Consume [-+]?
if
s
!=
""
{
c
:=
s
[
0
]
if
c
==
'-'
||
c
==
'+'
{
neg
=
c
==
'-'
s
=
s
[
1
:
]
}
}
// Special case: if all that is left is "0", this is zero.
if
s
==
"0"
{
return
0
,
nil
}
if
s
==
""
{
return
0
,
errors
.
New
(
"time: invalid duration "
+
orig
)
}
for
s
!=
""
{
g
:=
float64
(
0
)
// this element of the sequence
var
x
int
var
err
error
// The next character must be [0-9.]
if
!
(
s
[
0
]
==
'.'
||
(
'0'
<=
s
[
0
]
&&
s
[
0
]
<=
'9'
))
{
return
0
,
errors
.
New
(
"time: invalid duration "
+
orig
)
}
// Consume [0-9]*
pl
:=
len
(
s
)
x
,
s
,
err
=
leadingInt
(
s
)
if
err
!=
nil
{
return
0
,
errors
.
New
(
"time: invalid duration "
+
orig
)
}
g
=
float64
(
x
)
pre
:=
pl
!=
len
(
s
)
// whether we consumed anything before a period
// Consume (\.[0-9]*)?
post
:=
false
if
s
!=
""
&&
s
[
0
]
==
'.'
{
s
=
s
[
1
:
]
pl
:=
len
(
s
)
x
,
s
,
err
=
leadingInt
(
s
)
if
err
!=
nil
{
return
0
,
errors
.
New
(
"time: invalid duration "
+
orig
)
}
scale
:=
1
for
n
:=
pl
-
len
(
s
);
n
>
0
;
n
--
{
scale
*=
10
}
g
+=
float64
(
x
)
/
float64
(
scale
)
post
=
pl
!=
len
(
s
)
}
if
!
pre
&&
!
post
{
// no digits (e.g. ".s" or "-.s")
return
0
,
errors
.
New
(
"time: invalid duration "
+
orig
)
}
// Consume unit.
i
:=
0
for
;
i
<
len
(
s
);
i
++
{
c
:=
s
[
i
]
if
c
==
'.'
||
(
'0'
<=
c
&&
c
<=
'9'
)
{
break
}
}
if
i
==
0
{
return
0
,
errors
.
New
(
"time: missing unit in duration "
+
orig
)
}
u
:=
s
[
:
i
]
s
=
s
[
i
:
]
unit
,
ok
:=
unitMap
[
u
]
if
!
ok
{
return
0
,
errors
.
New
(
"time: unknown unit "
+
u
+
" in duration "
+
orig
)
}
f
+=
g
*
unit
}
if
neg
{
f
=
-
f
}
return
Duration
(
f
),
nil
}
src/pkg/time/time_test.go
View file @
f298d0ce
...
...
@@ -8,6 +8,7 @@ import (
"bytes"
"encoding/gob"
"encoding/json"
"math/rand"
"strconv"
"strings"
"testing"
...
...
@@ -816,6 +817,82 @@ func TestNotJSONEncodableTime(t *testing.T) {
}
}
var
parseDurationTests
=
[]
struct
{
in
string
ok
bool
want
Duration
}{
// simple
{
"0"
,
true
,
0
},
{
"5s"
,
true
,
5
*
Second
},
{
"30s"
,
true
,
30
*
Second
},
{
"1478s"
,
true
,
1478
*
Second
},
// sign
{
"-5s"
,
true
,
-
5
*
Second
},
{
"+5s"
,
true
,
5
*
Second
},
{
"-0"
,
true
,
0
},
{
"+0"
,
true
,
0
},
// decimal
{
"5.0s"
,
true
,
5
*
Second
},
{
"5.6s"
,
true
,
5
*
Second
+
600
*
Millisecond
},
{
"5.s"
,
true
,
5
*
Second
},
{
".5s"
,
true
,
500
*
Millisecond
},
{
"1.0s"
,
true
,
1
*
Second
},
{
"1.00s"
,
true
,
1
*
Second
},
{
"1.004s"
,
true
,
1
*
Second
+
4
*
Millisecond
},
{
"1.0040s"
,
true
,
1
*
Second
+
4
*
Millisecond
},
{
"100.00100s"
,
true
,
100
*
Second
+
1
*
Millisecond
},
// different units
{
"10ns"
,
true
,
10
*
Nanosecond
},
{
"11us"
,
true
,
11
*
Microsecond
},
{
"12µs"
,
true
,
12
*
Microsecond
},
// U+00B5
{
"12μs"
,
true
,
12
*
Microsecond
},
// U+03BC
{
"13ms"
,
true
,
13
*
Millisecond
},
{
"14s"
,
true
,
14
*
Second
},
{
"15m"
,
true
,
15
*
Minute
},
{
"16h"
,
true
,
16
*
Hour
},
// composite durations
{
"3h30m"
,
true
,
3
*
Hour
+
30
*
Minute
},
{
"10.5s4m"
,
true
,
4
*
Minute
+
10
*
Second
+
500
*
Millisecond
},
{
"-2m3.4s"
,
true
,
-
(
2
*
Minute
+
3
*
Second
+
400
*
Millisecond
)},
{
"1h2m3s4ms5us6ns"
,
true
,
1
*
Hour
+
2
*
Minute
+
3
*
Second
+
4
*
Millisecond
+
5
*
Microsecond
+
6
*
Nanosecond
},
{
"39h9m14.425s"
,
true
,
39
*
Hour
+
9
*
Minute
+
14
*
Second
+
425
*
Millisecond
},
// errors
{
""
,
false
,
0
},
{
"3"
,
false
,
0
},
{
"-"
,
false
,
0
},
{
"s"
,
false
,
0
},
{
"."
,
false
,
0
},
{
"-."
,
false
,
0
},
{
".s"
,
false
,
0
},
{
"+.s"
,
false
,
0
},
}
func
TestParseDuration
(
t
*
testing
.
T
)
{
for
_
,
tc
:=
range
parseDurationTests
{
d
,
err
:=
ParseDuration
(
tc
.
in
)
if
tc
.
ok
&&
(
err
!=
nil
||
d
!=
tc
.
want
)
{
t
.
Errorf
(
"ParseDuration(%q) = %v, %v, want %v, nil"
,
tc
.
in
,
d
,
err
,
tc
.
want
)
}
else
if
!
tc
.
ok
&&
err
==
nil
{
t
.
Errorf
(
"ParseDuration(%q) = _, nil, want _, non-nil"
,
tc
.
in
)
}
}
}
func
TestParseDurationRoundTrip
(
t
*
testing
.
T
)
{
for
i
:=
0
;
i
<
100
;
i
++
{
// Resolutions finer than milliseconds will result in
// imprecise round-trips.
d0
:=
Duration
(
rand
.
Int31
())
*
Millisecond
s
:=
d0
.
String
()
d1
,
err
:=
ParseDuration
(
s
)
if
err
!=
nil
||
d0
!=
d1
{
t
.
Errorf
(
"round-trip failed: %d => %q => %d, %v"
,
d0
,
s
,
d1
,
err
)
}
}
}
func
BenchmarkNow
(
b
*
testing
.
B
)
{
for
i
:=
0
;
i
<
b
.
N
;
i
++
{
Now
()
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment