您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

generalizedTime.go 2.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. package ber
  2. import (
  3. "bytes"
  4. "errors"
  5. "fmt"
  6. "strconv"
  7. "time"
  8. )
  9. // ErrInvalidTimeFormat is returned when the generalizedTime string was not correct.
  10. var ErrInvalidTimeFormat = errors.New("invalid time format")
  11. var zeroTime = time.Time{}
  12. // ParseGeneralizedTime parses a string value and if it conforms to
  13. // GeneralizedTime[^0] format, will return a time.Time for that value.
  14. //
  15. // [^0]: https://www.itu.int/rec/T-REC-X.690-201508-I/en Section 11.7
  16. func ParseGeneralizedTime(v []byte) (time.Time, error) {
  17. var format string
  18. var fract time.Duration
  19. str := []byte(DecodeString(v))
  20. tzIndex := bytes.IndexAny(str, "Z+-")
  21. if tzIndex < 0 {
  22. return zeroTime, ErrInvalidTimeFormat
  23. }
  24. dot := bytes.IndexAny(str, ".,")
  25. switch dot {
  26. case -1:
  27. switch tzIndex {
  28. case 10:
  29. format = `2006010215Z`
  30. case 12:
  31. format = `200601021504Z`
  32. case 14:
  33. format = `20060102150405Z`
  34. default:
  35. return zeroTime, ErrInvalidTimeFormat
  36. }
  37. case 10, 12:
  38. if tzIndex < dot {
  39. return zeroTime, ErrInvalidTimeFormat
  40. }
  41. // a "," is also allowed, but would not be parsed by time.Parse():
  42. str[dot] = '.'
  43. // If <minute> is omitted, then <fraction> represents a fraction of an
  44. // hour; otherwise, if <second> and <leap-second> are omitted, then
  45. // <fraction> represents a fraction of a minute; otherwise, <fraction>
  46. // represents a fraction of a second.
  47. // parse as float from dot to timezone
  48. f, err := strconv.ParseFloat(string(str[dot:tzIndex]), 64)
  49. if err != nil {
  50. return zeroTime, fmt.Errorf("failed to parse float: %s", err)
  51. }
  52. // ...and strip that part
  53. str = append(str[:dot], str[tzIndex:]...)
  54. tzIndex = dot
  55. if dot == 10 {
  56. fract = time.Duration(int64(f * float64(time.Hour)))
  57. format = `2006010215Z`
  58. } else {
  59. fract = time.Duration(int64(f * float64(time.Minute)))
  60. format = `200601021504Z`
  61. }
  62. case 14:
  63. if tzIndex < dot {
  64. return zeroTime, ErrInvalidTimeFormat
  65. }
  66. str[dot] = '.'
  67. // no need for fractional seconds, time.Parse() handles that
  68. format = `20060102150405Z`
  69. default:
  70. return zeroTime, ErrInvalidTimeFormat
  71. }
  72. l := len(str)
  73. switch l - tzIndex {
  74. case 1:
  75. if str[l-1] != 'Z' {
  76. return zeroTime, ErrInvalidTimeFormat
  77. }
  78. case 3:
  79. format += `0700`
  80. str = append(str, []byte("00")...)
  81. case 5:
  82. format += `0700`
  83. default:
  84. return zeroTime, ErrInvalidTimeFormat
  85. }
  86. t, err := time.Parse(format, string(str))
  87. if err != nil {
  88. return zeroTime, fmt.Errorf("%s: %s", ErrInvalidTimeFormat, err)
  89. }
  90. return t.Add(fract), nil
  91. }