OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libgo/] [go/] [time/] [format.go] - Blame information for rev 747

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 747 jeremybenn
// Copyright 2010 The Go Authors. All rights reserved.
2
// Use of this source code is governed by a BSD-style
3
// license that can be found in the LICENSE file.
4
 
5
package time
6
 
7
import "errors"
8
 
9
const (
10
        numeric = iota
11
        alphabetic
12
        separator
13
        plus
14
        minus
15
)
16
 
17
// These are predefined layouts for use in Time.Format.
18
// The standard time used in the layouts is:
19
//      Mon Jan 2 15:04:05 MST 2006  (MST is GMT-0700)
20
// which is Unix time 1136243045.
21
// (Think of it as 01/02 03:04:05PM '06 -0700.)
22
// To define your own format, write down what the standard
23
// time would look like formatted your way.
24
//
25
// Within the format string, an underscore _ represents a space that may be
26
// replaced by a digit if the following number (a day) has two digits; for
27
// compatibility with fixed-width Unix time formats.
28
//
29
// A decimal point followed by one or more zeros represents a fractional
30
// second. When parsing (only), the input may contain a fractional second
31
// field immediately after the seconds field, even if the layout does not
32
// signify its presence. In that case a decimal point followed by a maximal
33
// series of digits is parsed as a fractional second.
34
//
35
// Numeric time zone offsets format as follows:
36
//      -0700  ±hhmm
37
//      -07:00 ±hh:mm
38
// Replacing the sign in the format with a Z triggers
39
// the ISO 8601 behavior of printing Z instead of an
40
// offset for the UTC zone.  Thus:
41
//      Z0700  Z or ±hhmm
42
//      Z07:00 Z or ±hh:mm
43
const (
44
        ANSIC    = "Mon Jan _2 15:04:05 2006"
45
        UnixDate = "Mon Jan _2 15:04:05 MST 2006"
46
        RubyDate = "Mon Jan 02 15:04:05 -0700 2006"
47
        RFC822   = "02 Jan 06 1504 MST"
48
        RFC822Z  = "02 Jan 06 1504 -0700" // RFC822 with numeric zone
49
        RFC850   = "Monday, 02-Jan-06 15:04:05 MST"
50
        RFC1123  = "Mon, 02 Jan 2006 15:04:05 MST"
51
        RFC1123Z = "Mon, 02 Jan 2006 15:04:05 -0700" // RFC1123 with numeric zone
52
        RFC3339  = "2006-01-02T15:04:05Z07:00"
53
        Kitchen  = "3:04PM"
54
        // Handy time stamps.
55
        Stamp      = "Jan _2 15:04:05"
56
        StampMilli = "Jan _2 15:04:05.000"
57
        StampMicro = "Jan _2 15:04:05.000000"
58
        StampNano  = "Jan _2 15:04:05.000000000"
59
)
60
 
61
const (
62
        stdLongMonth      = "January"
63
        stdMonth          = "Jan"
64
        stdNumMonth       = "1"
65
        stdZeroMonth      = "01"
66
        stdLongWeekDay    = "Monday"
67
        stdWeekDay        = "Mon"
68
        stdDay            = "2"
69
        stdUnderDay       = "_2"
70
        stdZeroDay        = "02"
71
        stdHour           = "15"
72
        stdHour12         = "3"
73
        stdZeroHour12     = "03"
74
        stdMinute         = "4"
75
        stdZeroMinute     = "04"
76
        stdSecond         = "5"
77
        stdZeroSecond     = "05"
78
        stdLongYear       = "2006"
79
        stdYear           = "06"
80
        stdPM             = "PM"
81
        stdpm             = "pm"
82
        stdTZ             = "MST"
83
        stdISO8601TZ      = "Z0700"  // prints Z for UTC
84
        stdISO8601ColonTZ = "Z07:00" // prints Z for UTC
85
        stdNumTZ          = "-0700"  // always numeric
86
        stdNumShortTZ     = "-07"    // always numeric
87
        stdNumColonTZ     = "-07:00" // always numeric
88
)
89
 
90
// nextStdChunk finds the first occurrence of a std string in
91
// layout and returns the text before, the std string, and the text after.
92
func nextStdChunk(layout string) (prefix, std, suffix string) {
93
        for i := 0; i < len(layout); i++ {
94
                switch layout[i] {
95
                case 'J': // January, Jan
96
                        if len(layout) >= i+7 && layout[i:i+7] == stdLongMonth {
97
                                return layout[0:i], stdLongMonth, layout[i+7:]
98
                        }
99
                        if len(layout) >= i+3 && layout[i:i+3] == stdMonth {
100
                                return layout[0:i], stdMonth, layout[i+3:]
101
                        }
102
 
103
                case 'M': // Monday, Mon, MST
104
                        if len(layout) >= i+6 && layout[i:i+6] == stdLongWeekDay {
105
                                return layout[0:i], stdLongWeekDay, layout[i+6:]
106
                        }
107
                        if len(layout) >= i+3 {
108
                                if layout[i:i+3] == stdWeekDay {
109
                                        return layout[0:i], stdWeekDay, layout[i+3:]
110
                                }
111
                                if layout[i:i+3] == stdTZ {
112
                                        return layout[0:i], stdTZ, layout[i+3:]
113
                                }
114
                        }
115
 
116
                case '0': // 01, 02, 03, 04, 05, 06
117
                        if len(layout) >= i+2 && '1' <= layout[i+1] && layout[i+1] <= '6' {
118
                                return layout[0:i], layout[i : i+2], layout[i+2:]
119
                        }
120
 
121
                case '1': // 15, 1
122
                        if len(layout) >= i+2 && layout[i+1] == '5' {
123
                                return layout[0:i], stdHour, layout[i+2:]
124
                        }
125
                        return layout[0:i], stdNumMonth, layout[i+1:]
126
 
127
                case '2': // 2006, 2
128
                        if len(layout) >= i+4 && layout[i:i+4] == stdLongYear {
129
                                return layout[0:i], stdLongYear, layout[i+4:]
130
                        }
131
                        return layout[0:i], stdDay, layout[i+1:]
132
 
133
                case '_': // _2
134
                        if len(layout) >= i+2 && layout[i+1] == '2' {
135
                                return layout[0:i], stdUnderDay, layout[i+2:]
136
                        }
137
 
138
                case '3', '4', '5': // 3, 4, 5
139
                        return layout[0:i], layout[i : i+1], layout[i+1:]
140
 
141
                case 'P': // PM
142
                        if len(layout) >= i+2 && layout[i+1] == 'M' {
143
                                return layout[0:i], layout[i : i+2], layout[i+2:]
144
                        }
145
 
146
                case 'p': // pm
147
                        if len(layout) >= i+2 && layout[i+1] == 'm' {
148
                                return layout[0:i], layout[i : i+2], layout[i+2:]
149
                        }
150
 
151
                case '-': // -0700, -07:00, -07
152
                        if len(layout) >= i+5 && layout[i:i+5] == stdNumTZ {
153
                                return layout[0:i], layout[i : i+5], layout[i+5:]
154
                        }
155
                        if len(layout) >= i+6 && layout[i:i+6] == stdNumColonTZ {
156
                                return layout[0:i], layout[i : i+6], layout[i+6:]
157
                        }
158
                        if len(layout) >= i+3 && layout[i:i+3] == stdNumShortTZ {
159
                                return layout[0:i], layout[i : i+3], layout[i+3:]
160
                        }
161
                case 'Z': // Z0700, Z07:00
162
                        if len(layout) >= i+5 && layout[i:i+5] == stdISO8601TZ {
163
                                return layout[0:i], layout[i : i+5], layout[i+5:]
164
                        }
165
                        if len(layout) >= i+6 && layout[i:i+6] == stdISO8601ColonTZ {
166
                                return layout[0:i], layout[i : i+6], layout[i+6:]
167
                        }
168
                case '.': // .000 - multiple digits of zeros (only) for fractional seconds.
169
                        numZeros := 0
170
                        var j int
171
                        for j = i + 1; j < len(layout) && layout[j] == '0'; j++ {
172
                                numZeros++
173
                        }
174
                        // String of digits must end here - only fractional second is all zeros.
175
                        if numZeros > 0 && !isDigit(layout, j) {
176
                                return layout[0:i], layout[i : i+1+numZeros], layout[i+1+numZeros:]
177
                        }
178
                }
179
        }
180
        return layout, "", ""
181
}
182
 
183
var longDayNames = []string{
184
        "Sunday",
185
        "Monday",
186
        "Tuesday",
187
        "Wednesday",
188
        "Thursday",
189
        "Friday",
190
        "Saturday",
191
}
192
 
193
var shortDayNames = []string{
194
        "Sun",
195
        "Mon",
196
        "Tue",
197
        "Wed",
198
        "Thu",
199
        "Fri",
200
        "Sat",
201
}
202
 
203
var shortMonthNames = []string{
204
        "---",
205
        "Jan",
206
        "Feb",
207
        "Mar",
208
        "Apr",
209
        "May",
210
        "Jun",
211
        "Jul",
212
        "Aug",
213
        "Sep",
214
        "Oct",
215
        "Nov",
216
        "Dec",
217
}
218
 
219
var longMonthNames = []string{
220
        "---",
221
        "January",
222
        "February",
223
        "March",
224
        "April",
225
        "May",
226
        "June",
227
        "July",
228
        "August",
229
        "September",
230
        "October",
231
        "November",
232
        "December",
233
}
234
 
235
// match returns true if s1 and s2 match ignoring case.
236
// It is assumed s1 and s2 are the same length.
237
func match(s1, s2 string) bool {
238
        for i := 0; i < len(s1); i++ {
239
                c1 := s1[i]
240
                c2 := s2[i]
241
                if c1 != c2 {
242
                        // Switch to lower-case; 'a'-'A' is known to be a single bit.
243
                        c1 |= 'a' - 'A'
244
                        c2 |= 'a' - 'A'
245
                        if c1 != c2 || c1 < 'a' || c1 > 'z' {
246
                                return false
247
                        }
248
                }
249
        }
250
        return true
251
}
252
 
253
func lookup(tab []string, val string) (int, string, error) {
254
        for i, v := range tab {
255
                if len(val) >= len(v) && match(val[0:len(v)], v) {
256
                        return i, val[len(v):], nil
257
                }
258
        }
259
        return -1, val, errBad
260
}
261
 
262
// Duplicates functionality in strconv, but avoids dependency.
263
func itoa(x int) string {
264
        var buf [32]byte
265
        n := len(buf)
266
        if x == 0 {
267
                return "0"
268
        }
269
        u := uint(x)
270
        if x < 0 {
271
                u = -u
272
        }
273
        for u > 0 {
274
                n--
275
                buf[n] = byte(u%10 + '0')
276
                u /= 10
277
        }
278
        if x < 0 {
279
                n--
280
                buf[n] = '-'
281
        }
282
        return string(buf[n:])
283
}
284
 
285
// Never printed, just needs to be non-nil for return by atoi.
286
var atoiError = errors.New("time: invalid number")
287
 
288
// Duplicates functionality in strconv, but avoids dependency.
289
func atoi(s string) (x int, err error) {
290
        neg := false
291
        if s != "" && s[0] == '-' {
292
                neg = true
293
                s = s[1:]
294
        }
295
        x, rem, err := leadingInt(s)
296
        if err != nil || rem != "" {
297
                return 0, atoiError
298
        }
299
        if neg {
300
                x = -x
301
        }
302
        return x, nil
303
}
304
 
305
func pad(i int, padding string) string {
306
        s := itoa(i)
307
        if i < 10 {
308
                s = padding + s
309
        }
310
        return s
311
}
312
 
313
func zeroPad(i int) string { return pad(i, "0") }
314
 
315
// formatNano formats a fractional second, as nanoseconds.
316
func formatNano(nanosec, n int) string {
317
        // User might give us bad data. Make sure it's positive and in range.
318
        // They'll get nonsense output but it will have the right format.
319
        s := itoa(int(uint(nanosec) % 1e9))
320
        // Zero pad left without fmt.
321
        if len(s) < 9 {
322
                s = "000000000"[:9-len(s)] + s
323
        }
324
        if n > 9 {
325
                n = 9
326
        }
327
        return "." + s[:n]
328
}
329
 
330
// String returns the time formatted using the format string
331
//      "Mon Jan _2 15:04:05 -0700 MST 2006"
332
func (t Time) String() string {
333
        return t.Format("Mon Jan _2 15:04:05 -0700 MST 2006")
334
}
335
 
336
type buffer []byte
337
 
338
func (b *buffer) WriteString(s string) {
339
        *b = append(*b, s...)
340
}
341
 
342
func (b *buffer) String() string {
343
        return string([]byte(*b))
344
}
345
 
346
// Format returns a textual representation of the time value formatted
347
// according to layout.  The layout defines the format by showing the
348
// representation of a standard time, which is then used to describe
349
// the time to be formatted.  Predefined layouts ANSIC, UnixDate,
350
// RFC3339 and others describe standard representations. For more
351
// information about the formats, see the documentation for ANSIC.
352
func (t Time) Format(layout string) string {
353
        var (
354
                year  int = -1
355
                month Month
356
                day   int
357
                hour  int = -1
358
                min   int
359
                sec   int
360
                b     buffer
361
        )
362
        // Each iteration generates one std value.
363
        for {
364
                prefix, std, suffix := nextStdChunk(layout)
365
                b.WriteString(prefix)
366
                if std == "" {
367
                        break
368
                }
369
 
370
                // Compute year, month, day if needed.
371
                if year < 0 {
372
                        // Jan 01 02 2006
373
                        if a, z := std[0], std[len(std)-1]; a == 'J' || a == 'j' || z == '1' || z == '2' || z == '6' {
374
                                year, month, day = t.Date()
375
                        }
376
                }
377
 
378
                // Compute hour, minute, second if needed.
379
                if hour < 0 {
380
                        // 03 04 05 15 pm
381
                        if z := std[len(std)-1]; z == '3' || z == '4' || z == '5' || z == 'm' || z == 'M' {
382
                                hour, min, sec = t.Clock()
383
                        }
384
                }
385
 
386
                var p string
387
                switch std {
388
                case stdYear:
389
                        p = zeroPad(year % 100)
390
                case stdLongYear:
391
                        p = itoa(year)
392
                case stdMonth:
393
                        p = month.String()[:3]
394
                case stdLongMonth:
395
                        p = month.String()
396
                case stdNumMonth:
397
                        p = itoa(int(month))
398
                case stdZeroMonth:
399
                        p = zeroPad(int(month))
400
                case stdWeekDay:
401
                        p = t.Weekday().String()[:3]
402
                case stdLongWeekDay:
403
                        p = t.Weekday().String()
404
                case stdDay:
405
                        p = itoa(day)
406
                case stdUnderDay:
407
                        p = pad(day, " ")
408
                case stdZeroDay:
409
                        p = zeroPad(day)
410
                case stdHour:
411
                        p = zeroPad(hour)
412
                case stdHour12:
413
                        // Noon is 12PM, midnight is 12AM.
414
                        hr := hour % 12
415
                        if hr == 0 {
416
                                hr = 12
417
                        }
418
                        p = itoa(hr)
419
                case stdZeroHour12:
420
                        // Noon is 12PM, midnight is 12AM.
421
                        hr := hour % 12
422
                        if hr == 0 {
423
                                hr = 12
424
                        }
425
                        p = zeroPad(hr)
426
                case stdMinute:
427
                        p = itoa(min)
428
                case stdZeroMinute:
429
                        p = zeroPad(min)
430
                case stdSecond:
431
                        p = itoa(sec)
432
                case stdZeroSecond:
433
                        p = zeroPad(sec)
434
                case stdPM:
435
                        if hour >= 12 {
436
                                p = "PM"
437
                        } else {
438
                                p = "AM"
439
                        }
440
                case stdpm:
441
                        if hour >= 12 {
442
                                p = "pm"
443
                        } else {
444
                                p = "am"
445
                        }
446
                case stdISO8601TZ, stdISO8601ColonTZ, stdNumTZ, stdNumColonTZ:
447
                        // Ugly special case.  We cheat and take the "Z" variants
448
                        // to mean "the time zone as formatted for ISO 8601".
449
                        _, offset := t.Zone()
450
                        if offset == 0 && std[0] == 'Z' {
451
                                p = "Z"
452
                                break
453
                        }
454
                        zone := offset / 60 // convert to minutes
455
                        if zone < 0 {
456
                                p = "-"
457
                                zone = -zone
458
                        } else {
459
                                p = "+"
460
                        }
461
                        p += zeroPad(zone / 60)
462
                        if std == stdISO8601ColonTZ || std == stdNumColonTZ {
463
                                p += ":"
464
                        }
465
                        p += zeroPad(zone % 60)
466
                case stdTZ:
467
                        name, offset := t.Zone()
468
                        if name != "" {
469
                                p = name
470
                        } else {
471
                                // No time zone known for this time, but we must print one.
472
                                // Use the -0700 format.
473
                                zone := offset / 60 // convert to minutes
474
                                if zone < 0 {
475
                                        p = "-"
476
                                        zone = -zone
477
                                } else {
478
                                        p = "+"
479
                                }
480
                                p += zeroPad(zone / 60)
481
                                p += zeroPad(zone % 60)
482
                        }
483
                default:
484
                        if len(std) >= 2 && std[0:2] == ".0" {
485
                                p = formatNano(t.Nanosecond(), len(std)-1)
486
                        }
487
                }
488
                b.WriteString(p)
489
                layout = suffix
490
        }
491
        return b.String()
492
}
493
 
494
var errBad = errors.New("bad value for field") // placeholder not passed to user
495
 
496
// ParseError describes a problem parsing a time string.
497
type ParseError struct {
498
        Layout     string
499
        Value      string
500
        LayoutElem string
501
        ValueElem  string
502
        Message    string
503
}
504
 
505
func quote(s string) string {
506
        return "\"" + s + "\""
507
}
508
 
509
// Error returns the string representation of a ParseError.
510
func (e *ParseError) Error() string {
511
        if e.Message == "" {
512
                return "parsing time " +
513
                        quote(e.Value) + " as " +
514
                        quote(e.Layout) + ": cannot parse " +
515
                        quote(e.ValueElem) + " as " +
516
                        quote(e.LayoutElem)
517
        }
518
        return "parsing time " +
519
                quote(e.Value) + e.Message
520
}
521
 
522
// isDigit returns true if s[i] is a decimal digit, false if not or
523
// if s[i] is out of range.
524
func isDigit(s string, i int) bool {
525
        if len(s) <= i {
526
                return false
527
        }
528
        c := s[i]
529
        return '0' <= c && c <= '9'
530
}
531
 
532
// getnum parses s[0:1] or s[0:2] (fixed forces the latter)
533
// as a decimal integer and returns the integer and the
534
// remainder of the string.
535
func getnum(s string, fixed bool) (int, string, error) {
536
        if !isDigit(s, 0) {
537
                return 0, s, errBad
538
        }
539
        if !isDigit(s, 1) {
540
                if fixed {
541
                        return 0, s, errBad
542
                }
543
                return int(s[0] - '0'), s[1:], nil
544
        }
545
        return int(s[0]-'0')*10 + int(s[1]-'0'), s[2:], nil
546
}
547
 
548
func cutspace(s string) string {
549
        for len(s) > 0 && s[0] == ' ' {
550
                s = s[1:]
551
        }
552
        return s
553
}
554
 
555
// skip removes the given prefix from value,
556
// treating runs of space characters as equivalent.
557
func skip(value, prefix string) (string, error) {
558
        for len(prefix) > 0 {
559
                if prefix[0] == ' ' {
560
                        if len(value) > 0 && value[0] != ' ' {
561
                                return "", errBad
562
                        }
563
                        prefix = cutspace(prefix)
564
                        value = cutspace(value)
565
                        continue
566
                }
567
                if len(value) == 0 || value[0] != prefix[0] {
568
                        return "", errBad
569
                }
570
                prefix = prefix[1:]
571
                value = value[1:]
572
        }
573
        return value, nil
574
}
575
 
576
// Parse parses a formatted string and returns the time value it represents.
577
// The layout defines the format by showing the representation of a standard
578
// time, which is then used to describe the string to be parsed.  Predefined
579
// layouts ANSIC, UnixDate, RFC3339 and others describe standard
580
// representations.For more information about the formats, see the
581
// documentation for ANSIC.
582
//
583
// Elements omitted from the value are assumed to be zero, or when
584
// zero is impossible, one, so parsing "3:04pm" returns the time
585
// corresponding to Jan 1, year 0, 15:04:00 UTC.
586
// Years must be in the range 0000..9999. The day of the week is checked
587
// for syntax but it is otherwise ignored.
588
func Parse(layout, value string) (Time, error) {
589
        alayout, avalue := layout, value
590
        rangeErrString := "" // set if a value is out of range
591
        amSet := false       // do we need to subtract 12 from the hour for midnight?
592
        pmSet := false       // do we need to add 12 to the hour?
593
 
594
        // Time being constructed.
595
        var (
596
                year       int
597
                month      int = 1 // January
598
                day        int = 1
599
                hour       int
600
                min        int
601
                sec        int
602
                nsec       int
603
                z          *Location
604
                zoneOffset int = -1
605
                zoneName   string
606
        )
607
 
608
        // Each iteration processes one std value.
609
        for {
610
                var err error
611
                prefix, std, suffix := nextStdChunk(layout)
612
                value, err = skip(value, prefix)
613
                if err != nil {
614
                        return Time{}, &ParseError{alayout, avalue, prefix, value, ""}
615
                }
616
                if len(std) == 0 {
617
                        if len(value) != 0 {
618
                                return Time{}, &ParseError{alayout, avalue, "", value, ": extra text: " + value}
619
                        }
620
                        break
621
                }
622
                layout = suffix
623
                var p string
624
                switch std {
625
                case stdYear:
626
                        if len(value) < 2 {
627
                                err = errBad
628
                                break
629
                        }
630
                        p, value = value[0:2], value[2:]
631
                        year, err = atoi(p)
632
                        if year >= 69 { // Unix time starts Dec 31 1969 in some time zones
633
                                year += 1900
634
                        } else {
635
                                year += 2000
636
                        }
637
                case stdLongYear:
638
                        if len(value) < 4 || !isDigit(value, 0) {
639
                                err = errBad
640
                                break
641
                        }
642
                        p, value = value[0:4], value[4:]
643
                        year, err = atoi(p)
644
                case stdMonth:
645
                        month, value, err = lookup(shortMonthNames, value)
646
                case stdLongMonth:
647
                        month, value, err = lookup(longMonthNames, value)
648
                case stdNumMonth, stdZeroMonth:
649
                        month, value, err = getnum(value, std == stdZeroMonth)
650
                        if month <= 0 || 12 < month {
651
                                rangeErrString = "month"
652
                        }
653
                case stdWeekDay:
654
                        // Ignore weekday except for error checking.
655
                        _, value, err = lookup(shortDayNames, value)
656
                case stdLongWeekDay:
657
                        _, value, err = lookup(longDayNames, value)
658
                case stdDay, stdUnderDay, stdZeroDay:
659
                        if std == stdUnderDay && len(value) > 0 && value[0] == ' ' {
660
                                value = value[1:]
661
                        }
662
                        day, value, err = getnum(value, std == stdZeroDay)
663
                        if day < 0 || 31 < day {
664
                                rangeErrString = "day"
665
                        }
666
                case stdHour:
667
                        hour, value, err = getnum(value, false)
668
                        if hour < 0 || 24 <= hour {
669
                                rangeErrString = "hour"
670
                        }
671
                case stdHour12, stdZeroHour12:
672
                        hour, value, err = getnum(value, std == stdZeroHour12)
673
                        if hour < 0 || 12 < hour {
674
                                rangeErrString = "hour"
675
                        }
676
                case stdMinute, stdZeroMinute:
677
                        min, value, err = getnum(value, std == stdZeroMinute)
678
                        if min < 0 || 60 <= min {
679
                                rangeErrString = "minute"
680
                        }
681
                case stdSecond, stdZeroSecond:
682
                        sec, value, err = getnum(value, std == stdZeroSecond)
683
                        if sec < 0 || 60 <= sec {
684
                                rangeErrString = "second"
685
                        }
686
                        // Special case: do we have a fractional second but no
687
                        // fractional second in the format?
688
                        if len(value) > 2 && value[0] == '.' && isDigit(value, 1) {
689
                                _, std, _ := nextStdChunk(layout)
690
                                if len(std) > 0 && std[0] == '.' && isDigit(std, 1) {
691
                                        // Fractional second in the layout; proceed normally
692
                                        break
693
                                }
694
                                // No fractional second in the layout but we have one in the input.
695
                                n := 2
696
                                for ; n < len(value) && isDigit(value, n); n++ {
697
                                }
698
                                nsec, rangeErrString, err = parseNanoseconds(value, n)
699
                                value = value[n:]
700
                        }
701
                case stdPM:
702
                        if len(value) < 2 {
703
                                err = errBad
704
                                break
705
                        }
706
                        p, value = value[0:2], value[2:]
707
                        switch p {
708
                        case "PM":
709
                                pmSet = true
710
                        case "AM":
711
                                amSet = true
712
                        default:
713
                                err = errBad
714
                        }
715
                case stdpm:
716
                        if len(value) < 2 {
717
                                err = errBad
718
                                break
719
                        }
720
                        p, value = value[0:2], value[2:]
721
                        switch p {
722
                        case "pm":
723
                                pmSet = true
724
                        case "am":
725
                                amSet = true
726
                        default:
727
                                err = errBad
728
                        }
729
                case stdISO8601TZ, stdISO8601ColonTZ, stdNumTZ, stdNumShortTZ, stdNumColonTZ:
730
                        if std[0] == 'Z' && len(value) >= 1 && value[0] == 'Z' {
731
                                value = value[1:]
732
                                z = UTC
733
                                break
734
                        }
735
                        var sign, hour, min string
736
                        if std == stdISO8601ColonTZ || std == stdNumColonTZ {
737
                                if len(value) < 6 {
738
                                        err = errBad
739
                                        break
740
                                }
741
                                if value[3] != ':' {
742
                                        err = errBad
743
                                        break
744
                                }
745
                                sign, hour, min, value = value[0:1], value[1:3], value[4:6], value[6:]
746
                        } else if std == stdNumShortTZ {
747
                                if len(value) < 3 {
748
                                        err = errBad
749
                                        break
750
                                }
751
                                sign, hour, min, value = value[0:1], value[1:3], "00", value[3:]
752
                        } else {
753
                                if len(value) < 5 {
754
                                        err = errBad
755
                                        break
756
                                }
757
                                sign, hour, min, value = value[0:1], value[1:3], value[3:5], value[5:]
758
                        }
759
                        var hr, mm int
760
                        hr, err = atoi(hour)
761
                        if err == nil {
762
                                mm, err = atoi(min)
763
                        }
764
                        zoneOffset = (hr*60 + mm) * 60 // offset is in seconds
765
                        switch sign[0] {
766
                        case '+':
767
                        case '-':
768
                                zoneOffset = -zoneOffset
769
                        default:
770
                                err = errBad
771
                        }
772
                case stdTZ:
773
                        // Does it look like a time zone?
774
                        if len(value) >= 3 && value[0:3] == "UTC" {
775
                                z = UTC
776
                                value = value[3:]
777
                                break
778
                        }
779
 
780
                        if len(value) >= 3 && value[2] == 'T' {
781
                                p, value = value[0:3], value[3:]
782
                        } else if len(value) >= 4 && value[3] == 'T' {
783
                                p, value = value[0:4], value[4:]
784
                        } else {
785
                                err = errBad
786
                                break
787
                        }
788
                        for i := 0; i < len(p); i++ {
789
                                if p[i] < 'A' || 'Z' < p[i] {
790
                                        err = errBad
791
                                }
792
                        }
793
                        if err != nil {
794
                                break
795
                        }
796
                        // It's a valid format.
797
                        zoneName = p
798
                default:
799
                        if len(value) < len(std) {
800
                                err = errBad
801
                                break
802
                        }
803
                        if len(std) >= 2 && std[0:2] == ".0" {
804
                                nsec, rangeErrString, err = parseNanoseconds(value, len(std))
805
                                value = value[len(std):]
806
                        }
807
                }
808
                if rangeErrString != "" {
809
                        return Time{}, &ParseError{alayout, avalue, std, value, ": " + rangeErrString + " out of range"}
810
                }
811
                if err != nil {
812
                        return Time{}, &ParseError{alayout, avalue, std, value, ""}
813
                }
814
        }
815
        if pmSet && hour < 12 {
816
                hour += 12
817
        } else if amSet && hour == 12 {
818
                hour = 0
819
        }
820
 
821
        // TODO: be more aggressive checking day?
822
        if z != nil {
823
                return Date(year, Month(month), day, hour, min, sec, nsec, z), nil
824
        }
825
 
826
        t := Date(year, Month(month), day, hour, min, sec, nsec, UTC)
827
        if zoneOffset != -1 {
828
                t.sec -= int64(zoneOffset)
829
 
830
                // Look for local zone with the given offset.
831
                // If that zone was in effect at the given time, use it.
832
                name, offset, _, _, _ := Local.lookup(t.sec + internalToUnix)
833
                if offset == zoneOffset && (zoneName == "" || name == zoneName) {
834
                        t.loc = Local
835
                        return t, nil
836
                }
837
 
838
                // Otherwise create fake zone to record offset.
839
                t.loc = FixedZone(zoneName, zoneOffset)
840
                return t, nil
841
        }
842
 
843
        if zoneName != "" {
844
                // Look for local zone with the given offset.
845
                // If that zone was in effect at the given time, use it.
846
                offset, _, ok := Local.lookupName(zoneName)
847
                if ok {
848
                        name, off, _, _, _ := Local.lookup(t.sec + internalToUnix - int64(offset))
849
                        if name == zoneName && off == offset {
850
                                t.sec -= int64(offset)
851
                                t.loc = Local
852
                                return t, nil
853
                        }
854
                }
855
 
856
                // Otherwise, create fake zone with unknown offset.
857
                t.loc = FixedZone(zoneName, 0)
858
                return t, nil
859
        }
860
 
861
        // Otherwise, fall back to UTC.
862
        return t, nil
863
}
864
 
865
func parseNanoseconds(value string, nbytes int) (ns int, rangeErrString string, err error) {
866
        if value[0] != '.' {
867
                err = errBad
868
                return
869
        }
870
        ns, err = atoi(value[1:nbytes])
871
        if err != nil {
872
                return
873
        }
874
        if ns < 0 || 1e9 <= ns {
875
                rangeErrString = "fractional second"
876
                return
877
        }
878
        // We need nanoseconds, which means scaling by the number
879
        // of missing digits in the format, maximum length 10. If it's
880
        // longer than 10, we won't scale.
881
        scaleDigits := 10 - nbytes
882
        for i := 0; i < scaleDigits; i++ {
883
                ns *= 10
884
        }
885
        return
886
}
887
 
888
var errLeadingInt = errors.New("time: bad [0-9]*") // never printed
889
 
890
// leadingInt consumes the leading [0-9]* from s.
891
func leadingInt(s string) (x int, rem string, err error) {
892
        i := 0
893
        for ; i < len(s); i++ {
894
                c := s[i]
895
                if c < '0' || c > '9' {
896
                        break
897
                }
898
                if x >= (1<<31-10)/10 {
899
                        // overflow
900
                        return 0, "", errLeadingInt
901
                }
902
                x = x*10 + int(c) - '0'
903
        }
904
        return x, s[i:], nil
905
}
906
 
907
var unitMap = map[string]float64{
908
        "ns": float64(Nanosecond),
909
        "us": float64(Microsecond),
910
        "µs": float64(Microsecond), // U+00B5 = micro symbol
911
        "μs": float64(Microsecond), // U+03BC = Greek letter mu
912
        "ms": float64(Millisecond),
913
        "s":  float64(Second),
914
        "m":  float64(Minute),
915
        "h":  float64(Hour),
916
}
917
 
918
// ParseDuration parses a duration string.
919
// A duration string is a possibly signed sequence of
920
// decimal numbers, each with optional fraction and a unit suffix,
921
// such as "300ms", "-1.5h" or "2h45m".
922
// Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h".
923
func ParseDuration(s string) (Duration, error) {
924
        // [-+]?([0-9]*(\.[0-9]*)?[a-z]+)+
925
        orig := s
926
        f := float64(0)
927
        neg := false
928
 
929
        // Consume [-+]?
930
        if s != "" {
931
                c := s[0]
932
                if c == '-' || c == '+' {
933
                        neg = c == '-'
934
                        s = s[1:]
935
                }
936
        }
937
        // Special case: if all that is left is "0", this is zero.
938
        if s == "0" {
939
                return 0, nil
940
        }
941
        if s == "" {
942
                return 0, errors.New("time: invalid duration " + orig)
943
        }
944
        for s != "" {
945
                g := float64(0) // this element of the sequence
946
 
947
                var x int
948
                var err error
949
 
950
                // The next character must be [0-9.]
951
                if !(s[0] == '.' || ('0' <= s[0] && s[0] <= '9')) {
952
                        return 0, errors.New("time: invalid duration " + orig)
953
                }
954
                // Consume [0-9]*
955
                pl := len(s)
956
                x, s, err = leadingInt(s)
957
                if err != nil {
958
                        return 0, errors.New("time: invalid duration " + orig)
959
                }
960
                g = float64(x)
961
                pre := pl != len(s) // whether we consumed anything before a period
962
 
963
                // Consume (\.[0-9]*)?
964
                post := false
965
                if s != "" && s[0] == '.' {
966
                        s = s[1:]
967
                        pl := len(s)
968
                        x, s, err = leadingInt(s)
969
                        if err != nil {
970
                                return 0, errors.New("time: invalid duration " + orig)
971
                        }
972
                        scale := 1
973
                        for n := pl - len(s); n > 0; n-- {
974
                                scale *= 10
975
                        }
976
                        g += float64(x) / float64(scale)
977
                        post = pl != len(s)
978
                }
979
                if !pre && !post {
980
                        // no digits (e.g. ".s" or "-.s")
981
                        return 0, errors.New("time: invalid duration " + orig)
982
                }
983
 
984
                // Consume unit.
985
                i := 0
986
                for ; i < len(s); i++ {
987
                        c := s[i]
988
                        if c == '.' || ('0' <= c && c <= '9') {
989
                                break
990
                        }
991
                }
992
                if i == 0 {
993
                        return 0, errors.New("time: missing unit in duration " + orig)
994
                }
995
                u := s[:i]
996
                s = s[i:]
997
                unit, ok := unitMap[u]
998
                if !ok {
999
                        return 0, errors.New("time: unknown unit " + u + " in duration " + orig)
1000
                }
1001
 
1002
                f += g * unit
1003
        }
1004
 
1005
        if neg {
1006
                f = -f
1007
        }
1008
        return Duration(f), nil
1009
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.