localtime.go raw

   1  package toml
   2  
   3  import (
   4  	"fmt"
   5  	"strings"
   6  	"time"
   7  
   8  	"github.com/pelletier/go-toml/v2/unstable"
   9  )
  10  
  11  // LocalDate represents a calendar day in no specific timezone.
  12  type LocalDate struct {
  13  	Year  int
  14  	Month int
  15  	Day   int
  16  }
  17  
  18  // AsTime converts d into a specific time instance at midnight in zone.
  19  func (d LocalDate) AsTime(zone *time.Location) time.Time {
  20  	return time.Date(d.Year, time.Month(d.Month), d.Day, 0, 0, 0, 0, zone)
  21  }
  22  
  23  // String returns RFC 3339 representation of d.
  24  func (d LocalDate) String() string {
  25  	return fmt.Sprintf("%04d-%02d-%02d", d.Year, d.Month, d.Day)
  26  }
  27  
  28  // MarshalText returns RFC 3339 representation of d.
  29  func (d LocalDate) MarshalText() ([]byte, error) {
  30  	return []byte(d.String()), nil
  31  }
  32  
  33  // UnmarshalText parses b using RFC 3339 to fill d.
  34  func (d *LocalDate) UnmarshalText(b []byte) error {
  35  	res, err := parseLocalDate(b)
  36  	if err != nil {
  37  		return err
  38  	}
  39  	*d = res
  40  	return nil
  41  }
  42  
  43  // LocalTime represents a time of day of no specific day in no specific
  44  // timezone.
  45  type LocalTime struct {
  46  	Hour       int // Hour of the day: [0; 24[
  47  	Minute     int // Minute of the hour: [0; 60[
  48  	Second     int // Second of the minute: [0; 60[
  49  	Nanosecond int // Nanoseconds within the second:  [0, 1000000000[
  50  	Precision  int // Number of digits to display for Nanosecond.
  51  }
  52  
  53  // String returns RFC 3339 representation of d.
  54  // If d.Nanosecond and d.Precision are zero, the time won't have a nanosecond
  55  // component. If d.Nanosecond > 0 but d.Precision = 0, then the minimum number
  56  // of digits for nanoseconds is provided.
  57  func (d LocalTime) String() string {
  58  	s := fmt.Sprintf("%02d:%02d:%02d", d.Hour, d.Minute, d.Second)
  59  
  60  	if d.Precision > 0 {
  61  		s += fmt.Sprintf(".%09d", d.Nanosecond)[:d.Precision+1]
  62  	} else if d.Nanosecond > 0 {
  63  		// Nanoseconds are specified, but precision is not provided. Use the
  64  		// minimum.
  65  		s += strings.Trim(fmt.Sprintf(".%09d", d.Nanosecond), "0")
  66  	}
  67  
  68  	return s
  69  }
  70  
  71  // MarshalText returns RFC 3339 representation of d.
  72  func (d LocalTime) MarshalText() ([]byte, error) {
  73  	return []byte(d.String()), nil
  74  }
  75  
  76  // UnmarshalText parses b using RFC 3339 to fill d.
  77  func (d *LocalTime) UnmarshalText(b []byte) error {
  78  	res, left, err := parseLocalTime(b)
  79  	if err == nil && len(left) != 0 {
  80  		err = unstable.NewParserError(left, "extra characters")
  81  	}
  82  	if err != nil {
  83  		return err
  84  	}
  85  	*d = res
  86  	return nil
  87  }
  88  
  89  // LocalDateTime represents a time of a specific day in no specific timezone.
  90  type LocalDateTime struct {
  91  	LocalDate
  92  	LocalTime
  93  }
  94  
  95  // AsTime converts d into a specific time instance in zone.
  96  func (d LocalDateTime) AsTime(zone *time.Location) time.Time {
  97  	return time.Date(d.Year, time.Month(d.Month), d.Day, d.Hour, d.Minute, d.Second, d.Nanosecond, zone)
  98  }
  99  
 100  // String returns RFC 3339 representation of d.
 101  func (d LocalDateTime) String() string {
 102  	return d.LocalDate.String() + "T" + d.LocalTime.String()
 103  }
 104  
 105  // MarshalText returns RFC 3339 representation of d.
 106  func (d LocalDateTime) MarshalText() ([]byte, error) {
 107  	return []byte(d.String()), nil
 108  }
 109  
 110  // UnmarshalText parses b using RFC 3339 to fill d.
 111  func (d *LocalDateTime) UnmarshalText(data []byte) error {
 112  	res, left, err := parseLocalDateTime(data)
 113  	if err == nil && len(left) != 0 {
 114  		err = unstable.NewParserError(left, "extra characters")
 115  	}
 116  	if err != nil {
 117  		return err
 118  	}
 119  
 120  	*d = res
 121  	return nil
 122  }
 123