Skip to content

Commit f0c43a5

Browse files
committed
Add support to week of year specifier
Closes #5
1 parent 8699548 commit f0c43a5

File tree

4 files changed

+108
-109
lines changed

4 files changed

+108
-109
lines changed

.travis.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ notifications:
2424

2525
install:
2626
- go get github.com/go-playground/overalls
27-
- go get github.com/mattn/goveralls
2827

2928
script:
3029
- overalls -project=github.com/imperfectgo/go-strftime -covermode=atomic -- -race

README.md

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@
77

88
High performance C99-compatible `strftime` formatter for Go.
99

10-
**EXPERIMENTAL** Please DO NOT USE for now.
10+
## Caveats
11+
12+
**EXPERIMENTAL** Please test before use.
1113

1214
## Performance
1315

@@ -27,4 +29,5 @@ ok github.com/imperfectgo/go-strftime 4.245s
2729

2830
## License
2931

30-
See [License](./LICENSE) file.
32+
This project can be treated as a derived work of time package from golang standard library.
33+
Licensed under the Modified (3-clause) BSD license.

format.go

Lines changed: 41 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import (
1111

1212
const (
1313
_ = iota
14-
stdYield // Yielded chunk
14+
stdNop // Yielded chunk
1515
stdLongMonth = iota + stdNeedDate // "January"
1616
stdMonth // "Jan"
1717
stdNumMonth // "1"
@@ -20,6 +20,8 @@ const (
2020
stdZeroBasedNumWeekDay // numerical week representation (0 - Sunday ~ 6 - Saturday)
2121
stdNumWeekDay // numerical week representation (1 - Monday ~ 7- Sunday)
2222
stdWeekDay // "Mon"
23+
stdWeekOfYear // week of the year (Sunday first)
24+
stdMonFirstWeekOfYear // week of the year (Monday first)
2325
stdDay // "2"
2426
stdUnderDay // "_2"
2527
stdZeroDay // "02"
@@ -33,7 +35,7 @@ const (
3335
stdLongYear = iota + stdNeedDate // "2006"
3436
stdYear // "06"
3537
stdFirstTwoDigitYear // "20"
36-
stdYearDay // day of the year as a decimal number (range [001,366])
38+
stdYearDay // day of the year (range [001,366])
3739
stdISO8601WeekYear = iota + stdNeedISOISO8601Week // last two digits of ISO 8601 week-based year
3840
stdISO8601LongWeekYear // ISO 8601 week-based year
3941
stdISO8601Week // ISO 8601 week
@@ -104,7 +106,7 @@ func AppendFormat(b []byte, t time.Time, layout string) []byte {
104106
}
105107

106108
switch std & stdMask {
107-
case stdYield:
109+
case stdNop:
108110
continue
109111
case stdISO8601WeekYear:
110112
b = appendInt(b, iso8601WeekYear%100, 2)
@@ -129,8 +131,8 @@ func AppendFormat(b []byte, t time.Time, layout string) []byte {
129131
case stdLongMonth:
130132
m := month.String()
131133
b = append(b, m...)
132-
case stdNumMonth:
133-
b = appendInt(b, int(month), 0)
134+
//case stdNumMonth:
135+
// b = appendInt(b, int(month), 0)
134136
case stdZeroMonth:
135137
b = appendInt(b, int(month), 2)
136138
case stdWeekDay:
@@ -147,6 +149,14 @@ func AppendFormat(b []byte, t time.Time, layout string) []byte {
147149
w = 7
148150
}
149151
b = appendInt(b, w, 0)
152+
case stdWeekOfYear, stdMonFirstWeekOfYear:
153+
w := int(absWeekday(abs))
154+
n := w - (std - stdWeekOfYear)
155+
if n < 0 {
156+
n = 7
157+
}
158+
n = ((yday - n) / 7) + 1
159+
b = appendInt(b, n, 2)
150160
case stdDay:
151161
b = appendInt(b, day, 0)
152162
case stdUnderDay:
@@ -158,26 +168,26 @@ func AppendFormat(b []byte, t time.Time, layout string) []byte {
158168
b = appendInt(b, day, 2)
159169
case stdHour:
160170
b = appendInt(b, hour, 2)
161-
case stdHour12:
162-
// Noon is 12PM, midnight is 12AM.
163-
hr := hour % 12
164-
if hr == 0 {
165-
hr = 12
166-
}
167-
b = appendInt(b, hr, 0)
171+
//case stdHour12:
172+
// // Noon is 12PM, midnight is 12AM.
173+
// hr := hour % 12
174+
// if hr == 0 {
175+
// hr = 12
176+
// }
177+
// b = appendInt(b, hr, 0)
168178
case stdZeroHour12:
169179
// Noon is 12PM, midnight is 12AM.
170180
hr := hour % 12
171181
if hr == 0 {
172182
hr = 12
173183
}
174184
b = appendInt(b, hr, 2)
175-
case stdMinute:
176-
b = appendInt(b, min, 0)
185+
//case stdMinute:
186+
// b = appendInt(b, min, 0)
177187
case stdZeroMinute:
178188
b = appendInt(b, min, 2)
179-
case stdSecond:
180-
b = appendInt(b, sec, 0)
189+
//case stdSecond:
190+
// b = appendInt(b, sec, 0)
181191
case stdZeroSecond:
182192
b = appendInt(b, sec, 2)
183193
case stdPM:
@@ -208,17 +218,6 @@ func AppendFormat(b []byte, t time.Time, layout string) []byte {
208218
b = append(b, name...)
209219
break
210220
}
211-
// No time zone known for this time, but we must print one.
212-
// Use the -0700 laylout.
213-
zone := offset / 60 // convert to minutes
214-
if zone < 0 {
215-
b = append(b, '-')
216-
zone = -zone
217-
} else {
218-
b = append(b, '+')
219-
}
220-
b = appendInt(b, zone/60, 2)
221-
b = appendInt(b, zone%60, 2)
222221
case stdFracSecond0, stdFracSecond9:
223222
b = formatNano(b, uint(t.Nanosecond()), std>>stdArgShift, std&stdMask == stdFracSecond9)
224223
}
@@ -250,21 +249,21 @@ func nextStdChunk(layout string) (prefix string, std int, suffix string) {
250249
case 'B': // January
251250
return layout[0:specPos], stdLongMonth, layout[i+1:]
252251
case 'c': // "Mon Jan _2 15:04:05 2006" (assumes "C" locale)
253-
return layout[0:specPos], stdYield, "%a %b %e %H:%M:%S %Y" + layout[i+1:]
252+
return layout[0:specPos], stdNop, "%a %b %e %H:%M:%S %Y" + layout[i+1:]
254253
case 'C': // 20
255254
return layout[0:specPos], stdFirstTwoDigitYear, layout[i+1:]
256255
case 'd': // 02
257256
return layout[0:specPos], stdZeroDay, layout[i+1:]
258257
case 'D': // %m/%d/%y
259-
return layout[0:specPos], stdYield, "%m/%d/%y" + layout[i+1:]
258+
return layout[0:specPos], stdNop, "%m/%d/%y" + layout[i+1:]
260259
case 'e': // _2
261260
return layout[0:specPos], stdUnderDay, layout[i+1:]
262261
case 'f': // fraction seconds in microseconds (Python)
263262
std = stdFracSecond0
264263
std |= 6 << stdArgShift // microseconds precision
265264
return layout[0:specPos], std, layout[i+1:]
266265
case 'F': // %Y-%m-%d
267-
return layout[0:specPos], stdYield, "%Y-%m-%d" + layout[i+1:]
266+
return layout[0:specPos], stdNop, "%Y-%m-%d" + layout[i+1:]
268267
case 'g':
269268
return layout[0:specPos], stdISO8601WeekYear, layout[i+1:]
270269
case 'G':
@@ -280,35 +279,35 @@ func nextStdChunk(layout string) (prefix string, std int, suffix string) {
280279
case 'M':
281280
return layout[0:specPos], stdZeroMinute, layout[i+1:]
282281
case 'n':
283-
return layout[0:specPos] + "\n", stdYield, layout[i+1:]
282+
return layout[0:specPos] + "\n", stdNop, layout[i+1:]
284283
case 'p':
285284
return layout[0:specPos], stdPM, layout[i+1:]
286285
case 'P':
287286
return layout[0:specPos], stdpm, layout[i+1:]
288287
case 'r':
289-
return layout[0:specPos], stdYield, "%I:%M:%S %p" + layout[i+1:]
288+
return layout[0:specPos], stdNop, "%I:%M:%S %p" + layout[i+1:]
290289
case 'R': // %H:%M"
291-
return layout[0:specPos], stdYield, "%H:%M" + layout[i+1:]
290+
return layout[0:specPos], stdNop, "%H:%M" + layout[i+1:]
292291
case 'S':
293292
return layout[0:specPos], stdZeroSecond, layout[i+1:]
294293
case 't':
295-
return layout[0:specPos] + "\t", stdYield, layout[i+1:]
294+
return layout[0:specPos] + "\t", stdNop, layout[i+1:]
296295
case 'T': // %H:%M:%S
297-
return layout[0:specPos], stdYield, "%H:%M:%S" + layout[i+1:]
296+
return layout[0:specPos], stdNop, "%H:%M:%S" + layout[i+1:]
298297
case 'u': // weekday as a decimal number, where Monday is 1
299298
return layout[0:specPos], stdNumWeekDay, layout[i+1:]
300-
case 'U':
301-
// TODO week of the year as a decimal number (Sunday is the first day of the week)
299+
case 'U': // week of the year as a decimal number (Sunday is the first day of the week)
300+
return layout[0:specPos], stdWeekOfYear, layout[i+1:]
302301
case 'V':
303302
return layout[0:specPos], stdISO8601Week, layout[i+1:]
304303
case 'w':
305304
return layout[0:specPos], stdZeroBasedNumWeekDay, layout[i+1:]
306-
case 'W':
307-
// TODO: week of the year as a decimal number (Monday is the first day of the week)
305+
case 'W': // week of the year as a decimal number (Monday is the first day of the week)
306+
return layout[0:specPos], stdMonFirstWeekOfYear, layout[i+1:]
308307
case 'x': // locale depended date representation (assumes "C" locale)
309-
return layout[0:specPos], stdYield, "%m/%d/%Y" + layout[i+1:]
308+
return layout[0:specPos], stdNop, "%m/%d/%Y" + layout[i+1:]
310309
case 'X': // locale depended time representation (assumes "C" locale)
311-
return layout[0:specPos], stdYield, "%H:%M:%S" + layout[i+1:]
310+
return layout[0:specPos], stdNop, "%H:%M:%S" + layout[i+1:]
312311
case 'y':
313312
return layout[0:specPos], stdYear, layout[i+1:]
314313
case 'Y':
@@ -318,7 +317,7 @@ func nextStdChunk(layout string) (prefix string, std int, suffix string) {
318317
case 'Z':
319318
return layout[0:specPos], stdTZ, layout[i+1:]
320319
case '%':
321-
return layout[0:specPos] + "%", stdYield, layout[i+1:]
320+
return layout[0:specPos] + "%", stdNop, layout[i+1:]
322321
}
323322

324323
specPos = -1

format_test.go

Lines changed: 62 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
//
1414
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1515
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16-
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16+
// FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE
1717
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1818
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
1919
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
@@ -22,7 +22,6 @@
2222
package strftime
2323

2424
import (
25-
"fmt"
2625
"testing"
2726
"time"
2827
)
@@ -35,76 +34,75 @@ var (
3534

3635
tc = []struct {
3736
time time.Time
38-
laylout string
37+
layout string
3938
expected string
4039
}{
41-
{time: t1, laylout: "%", expected: "%"},
42-
{time: t1, laylout: "%%", expected: "%"},
43-
{time: t1, laylout: "%Q", expected: "%Q"},
44-
{time: t1, laylout: "%%n", expected: "%n"},
45-
{time: t1, laylout: "%%t", expected: "%t"},
46-
{time: t1, laylout: "%n%t", expected: "\n\t"},
47-
{time: t1, laylout: "%a", expected: "Mon"},
48-
{time: t1, laylout: "%A", expected: "Monday"},
49-
{time: t1, laylout: "%b", expected: "Jul"},
50-
{time: t1, laylout: "%h", expected: "Jul"},
51-
{time: t1, laylout: "%B", expected: "July"},
52-
{time: t1, laylout: "%c", expected: "Mon Jul 9 13:14:15 2018"},
53-
{time: t1, laylout: "%C", expected: "20"},
54-
{time: t1, laylout: "%d", expected: "09"},
55-
{time: t1, laylout: "%D", expected: "07/09/18"},
56-
{time: t1, laylout: "%e", expected: " 9"},
57-
{time: t1, laylout: "%F", expected: "2018-07-09"},
58-
{time: t1, laylout: "%g", expected: "18"},
59-
{time: t1, laylout: "%G", expected: "2018"},
60-
{time: t1, laylout: "%H", expected: "13"},
61-
{time: t1, laylout: "%I", expected: "01"},
62-
{time: t1, laylout: "%j", expected: "190"},
63-
{time: t1, laylout: "%m", expected: "07"},
64-
{time: t1, laylout: "%M", expected: "14"},
65-
{time: t1, laylout: "%n", expected: "\n"},
66-
{time: t1, laylout: "%p", expected: "PM"},
67-
{time: t2, laylout: "%p", expected: "AM"},
68-
{time: t1, laylout: "%P", expected: "pm"},
69-
{time: t2, laylout: "%P", expected: "am"},
70-
{time: t1, laylout: "%r", expected: "01:14:15 PM"},
71-
{time: t2, laylout: "%r", expected: "04:45:59 AM"},
72-
{time: t1, laylout: "%R", expected: "13:14"},
73-
{time: t2, laylout: "%R", expected: "04:45"},
74-
{time: t1, laylout: "%S", expected: "15"},
75-
{time: t1, laylout: "%t", expected: "\t"},
76-
{time: t1, laylout: "%T", expected: "13:14:15"},
77-
{time: t2, laylout: "%T", expected: "04:45:59"},
78-
{time: t1, laylout: "%u", expected: "1"},
79-
{time: t2, laylout: "%u", expected: "7"},
80-
{time: t1, laylout: "%V", expected: "28"},
81-
{time: t3, laylout: "%V", expected: "53"}, // 3 January days in this week.
82-
{time: t4, laylout: "%V", expected: "01"}, // 4 January days in this week.
83-
{time: t1, laylout: "%w", expected: "1"},
84-
{time: t2, laylout: "%w", expected: "0"},
85-
{time: t1, laylout: "%x", expected: "07/09/2018"},
86-
{time: t1, laylout: "%X", expected: "13:14:15"},
87-
{time: t2, laylout: "%X", expected: "04:45:59"},
88-
{time: t1, laylout: "%y", expected: "18"},
89-
{time: t1, laylout: "%Y", expected: "2018"},
90-
{time: t1, laylout: "%z", expected: "+0000"},
91-
{time: t1, laylout: "%Z", expected: "UTC"},
92-
{time: t1, laylout: "foo", expected: "foo"},
93-
{time: t1, laylout: "bar%", expected: "bar%"},
94-
{time: t1, laylout: "%1", expected: "%1"},
95-
{time: t1, laylout: "%Y-%m-%dtest\n\t%Z", expected: "2018-07-09test\n\tUTC"},
40+
{time: t1, layout: "%", expected: "%"},
41+
{time: t1, layout: "%%", expected: "%"},
42+
{time: t1, layout: "%Q", expected: "%Q"},
43+
{time: t1, layout: "%%n", expected: "%n"},
44+
{time: t1, layout: "%%t", expected: "%t"},
45+
{time: t1, layout: "%n%t", expected: "\n\t"},
46+
{time: t1, layout: "%a", expected: "Mon"},
47+
{time: t1, layout: "%A", expected: "Monday"},
48+
{time: t1, layout: "%b", expected: "Jul"},
49+
{time: t1, layout: "%h", expected: "Jul"},
50+
{time: t1, layout: "%B", expected: "July"},
51+
{time: t1, layout: "%c", expected: "Mon Jul 9 13:14:15 2018"},
52+
{time: t1, layout: "%C", expected: "20"},
53+
{time: t1, layout: "%d", expected: "09"},
54+
{time: t1, layout: "%D", expected: "07/09/18"},
55+
{time: t1, layout: "%e", expected: " 9"},
56+
{time: t1, layout: "%F", expected: "2018-07-09"},
57+
{time: t1, layout: "%g", expected: "18"},
58+
{time: t1, layout: "%G", expected: "2018"},
59+
{time: t1, layout: "%H", expected: "13"},
60+
{time: t1, layout: "%I", expected: "01"},
61+
{time: t1, layout: "%j", expected: "190"},
62+
{time: t1, layout: "%m", expected: "07"},
63+
{time: t1, layout: "%M", expected: "14"},
64+
{time: t1, layout: "%n", expected: "\n"},
65+
{time: t1, layout: "%p", expected: "PM"},
66+
{time: t2, layout: "%p", expected: "AM"},
67+
{time: t1, layout: "%P", expected: "pm"},
68+
{time: t2, layout: "%P", expected: "am"},
69+
{time: t1, layout: "%r", expected: "01:14:15 PM"},
70+
{time: t2, layout: "%r", expected: "04:45:59 AM"},
71+
{time: t1, layout: "%R", expected: "13:14"},
72+
{time: t2, layout: "%R", expected: "04:45"},
73+
{time: t1, layout: "%S", expected: "15"},
74+
{time: t1, layout: "%t", expected: "\t"},
75+
{time: t1, layout: "%T", expected: "13:14:15"},
76+
{time: t2, layout: "%T", expected: "04:45:59"},
77+
{time: t1, layout: "%u", expected: "1"},
78+
{time: t2, layout: "%u", expected: "7"},
79+
{time: t1, layout: "%V", expected: "28"},
80+
{time: t3, layout: "%V", expected: "53"}, // 3 January days in this week.
81+
{time: t4, layout: "%V", expected: "01"}, // 4 January days in this week.
82+
{time: t1, layout: "%w", expected: "1"},
83+
{time: t2, layout: "%w", expected: "0"},
84+
{time: t1, layout: "%x", expected: "07/09/2018"},
85+
{time: t1, layout: "%X", expected: "13:14:15"},
86+
{time: t2, layout: "%X", expected: "04:45:59"},
87+
{time: t1, layout: "%y", expected: "18"},
88+
{time: t1, layout: "%Y", expected: "2018"},
89+
{time: t1, layout: "%z", expected: "+0000"},
90+
{time: t1, layout: "%Z", expected: "UTC"},
91+
{time: t1, layout: "foo", expected: "foo"},
92+
{time: t1, layout: "bar%", expected: "bar%"},
93+
{time: t1, layout: "%1", expected: "%1"},
94+
{time: t1, layout: "%U %W", expected: "27 28"},
95+
{time: t1, layout: "%Y-%m-%dtest\n\t%Z", expected: "2018-07-09test\n\tUTC"},
9696
}
9797
)
9898

9999
func TestFormat(t *testing.T) {
100100

101101
for i := range tc {
102102
c := tc[i]
103-
t.Run(fmt.Sprintf("layout: %s", c.laylout), func(t *testing.T) {
104-
actual := Format(c.time, c.laylout)
105-
if actual != c.expected {
106-
t.Errorf("expected: %q; actual: %q", c.expected, actual)
107-
}
108-
})
103+
actual := Format(c.time, c.layout)
104+
if actual != c.expected {
105+
t.Errorf("Test layout `%s`: expected: %q; actual: %q", c.layout, c.expected, actual)
106+
}
109107
}
110108
}

0 commit comments

Comments
 (0)