github.com/enbility/spine-go@v0.7.0/model/commondatatypes_additions.go (about)

     1  package model
     2  
     3  import (
     4  	"encoding/json"
     5  	"errors"
     6  	"fmt"
     7  	"math"
     8  	"strconv"
     9  	"strings"
    10  	"time"
    11  
    12  	"github.com/rickb777/date/period"
    13  )
    14  
    15  // TimePeriodType
    16  
    17  func NewTimePeriodTypeWithRelativeEndTime(duration time.Duration) *TimePeriodType {
    18  	now := time.Now().UTC()
    19  	endTime := now.Add(duration)
    20  	value := &TimePeriodType{
    21  		EndTime: NewAbsoluteOrRelativeTimeTypeFromTime(endTime),
    22  	}
    23  	return value
    24  }
    25  
    26  // helper type to modify EndTime field value in json.Marshal and
    27  // json.Unmarshal to allow provide accurate relative durations
    28  //
    29  // If only EndTime is provided and it is a duration, it has to
    30  // decrease over time. To do this without actually changing
    31  // the data, it will always be transformed into an absolute time
    32  // in Marshal and returned as an up to date relative duration
    33  // in Unmarshal
    34  type tempTimePeriodType TimePeriodType
    35  
    36  func setTimePeriodTypeEndTime(t *tempTimePeriodType) {
    37  	if t.StartTime != nil || t.EndTime == nil {
    38  		return
    39  	}
    40  
    41  	duration, err := t.EndTime.GetTimeDuration()
    42  	if err != nil {
    43  		return
    44  	}
    45  
    46  	time := time.Now().UTC().Add(duration)
    47  	t.EndTime = NewAbsoluteOrRelativeTimeTypeFromTime(time)
    48  }
    49  
    50  func getTimePeriodTypeDuration(t *TimePeriodType) (time.Duration, error) {
    51  	if t.StartTime != nil || t.EndTime == nil {
    52  		return 0, errors.New("invalid data format")
    53  	}
    54  
    55  	if t.EndTime.IsRelativeTime() {
    56  		return getTimeDurationFromString(string(*t.EndTime))
    57  	}
    58  
    59  	endTime, err := t.EndTime.GetTime()
    60  	if err != nil {
    61  		return 0, err
    62  	}
    63  
    64  	now := time.Now().UTC()
    65  	duration := endTime.Sub(now)
    66  	duration = duration.Round(time.Second)
    67  
    68  	return duration, nil
    69  }
    70  
    71  // when startTime is empty and endTime is an absolute time,
    72  // then endTime should be returned as an relative timestamp
    73  func (t TimePeriodType) MarshalJSON() ([]byte, error) {
    74  	temp := tempTimePeriodType(t)
    75  
    76  	if duration, err := getTimePeriodTypeDuration(&t); err == nil {
    77  		temp.EndTime = NewAbsoluteOrRelativeTimeTypeFromDuration(duration)
    78  	}
    79  
    80  	return json.Marshal(temp)
    81  }
    82  
    83  // when startTime is empty and endTime is a relative time,
    84  // then endTime should be written as an absolute timestamp
    85  func (t *TimePeriodType) UnmarshalJSON(data []byte) error {
    86  	var temp tempTimePeriodType
    87  	if err := json.Unmarshal(data, &temp); err != nil {
    88  		return err
    89  	}
    90  
    91  	setTimePeriodTypeEndTime(&temp)
    92  
    93  	*t = TimePeriodType(temp)
    94  
    95  	return nil
    96  }
    97  
    98  // Return the current duration if StartTime is nil and EndTime is not
    99  // otherwise returns an error
   100  func (t *TimePeriodType) GetDuration() (time.Duration, error) {
   101  	return getTimePeriodTypeDuration(t)
   102  }
   103  
   104  // TimeType xs:time
   105  
   106  func NewTimeType(t string) *TimeType {
   107  	value := TimeType(t)
   108  	return &value
   109  }
   110  
   111  func (s *TimeType) GetTime() (time.Time, error) {
   112  	allowedFormats := []string{
   113  		"15:04:05.999999999",
   114  		"15:04:05.999999999Z",
   115  		"15:04:05",
   116  		"15:04:05Z",
   117  		"15:04:05+07:00",
   118  		"15:04:05-07:00",
   119  	}
   120  
   121  	for _, format := range allowedFormats {
   122  		if value, err := time.ParseInLocation(format, string(*s), time.UTC); err == nil {
   123  			return value, nil
   124  		}
   125  	}
   126  
   127  	return time.Time{}, errors.New("unsupported time format")
   128  }
   129  
   130  // DateType xs:date
   131  
   132  func NewDateType(t string) *DateType {
   133  	value := DateType(t)
   134  	return &value
   135  }
   136  
   137  // 2001-10-26, 2001-10-26+02:00, 2001-10-26Z, 2001-10-26+00:00, -2001-10-26, or -20000-04-01
   138  func (d *DateType) GetTime() (time.Time, error) {
   139  	allowedFormats := []string{
   140  		"2006-01-02",
   141  		"2006-01-02Z",
   142  		"2006-01-02+07:00",
   143  	}
   144  
   145  	for _, format := range allowedFormats {
   146  		if value, err := time.ParseInLocation(format, string(*d), time.UTC); err == nil {
   147  			return value, nil
   148  		}
   149  	}
   150  
   151  	return time.Time{}, errors.New("unsupported date format")
   152  }
   153  
   154  // DateTimeType xs:datetime
   155  
   156  func NewDateTimeType(t string) *DateTimeType {
   157  	value := DateTimeType(t)
   158  	return &value
   159  }
   160  
   161  func NewDateTimeTypeFromTime(t time.Time) *DateTimeType {
   162  	s := t.Round(time.Second).UTC().Format("2006-01-02T15:04:05Z")
   163  	return NewDateTimeType(s)
   164  }
   165  
   166  func (d *DateTimeType) GetTime() (time.Time, error) {
   167  	allowedFormats := []string{
   168  		"2006-01-02T15:04:05.999999999",
   169  		"2006-01-02T15:04:05.999999999Z",
   170  		"2006-01-02T15:04:05",
   171  		"2006-01-02T15:04:05Z",
   172  	}
   173  
   174  	for _, format := range allowedFormats {
   175  		if value, err := time.ParseInLocation(format, string(*d), time.UTC); err == nil {
   176  			return value, nil
   177  		}
   178  	}
   179  
   180  	return time.Time{}, errors.New("unsupported datetime format")
   181  }
   182  
   183  // DurationType
   184  
   185  func NewDurationType(duration time.Duration) *DurationType {
   186  	d, _ := period.NewOf(duration)
   187  	value := DurationType(d.String())
   188  	return &value
   189  }
   190  
   191  func (d *DurationType) GetTimeDuration() (time.Duration, error) {
   192  	return getTimeDurationFromString(string(*d))
   193  }
   194  
   195  // helper for DurationType and AbsoluteOrRelativeTimeType
   196  func getTimeDurationFromString(s string) (time.Duration, error) {
   197  	p, err := period.Parse(string(s))
   198  	if err != nil {
   199  		return 0, err
   200  	}
   201  
   202  	return p.DurationApprox(), nil
   203  }
   204  
   205  // AbsoluteOrRelativeTimeType
   206  // can be of type TimeType or DurationType
   207  
   208  func NewAbsoluteOrRelativeTimeType(s string) *AbsoluteOrRelativeTimeType {
   209  	value := AbsoluteOrRelativeTimeType(s)
   210  	return &value
   211  }
   212  
   213  func NewAbsoluteOrRelativeTimeTypeFromDuration(t time.Duration) *AbsoluteOrRelativeTimeType {
   214  	s := NewDurationType(t)
   215  	value := AbsoluteOrRelativeTimeType(*s)
   216  	return &value
   217  }
   218  
   219  func NewAbsoluteOrRelativeTimeTypeFromTime(t time.Time) *AbsoluteOrRelativeTimeType {
   220  	s := NewDateTimeTypeFromTime(t)
   221  	value := AbsoluteOrRelativeTimeType(*s)
   222  	return &value
   223  }
   224  
   225  func (a *AbsoluteOrRelativeTimeType) GetDateTimeType() *DateTimeType {
   226  	value := NewDateTimeType(string(*a))
   227  	return value
   228  }
   229  
   230  func (a *AbsoluteOrRelativeTimeType) GetTime() (time.Time, error) {
   231  	value := NewDateTimeType(string(*a))
   232  	t, err := value.GetTime()
   233  	if err == nil {
   234  		return t, nil
   235  	}
   236  
   237  	// Check if this is a relative time
   238  	d, err := getTimeDurationFromString(string(*a))
   239  	if err != nil {
   240  		return time.Time{}, err
   241  	}
   242  	r := time.Now().Add(d)
   243  	return r, nil
   244  }
   245  
   246  func (a *AbsoluteOrRelativeTimeType) IsRelativeTime() bool {
   247  	_, err := getTimeDurationFromString(string(*a))
   248  	return err == nil
   249  }
   250  
   251  func (a *AbsoluteOrRelativeTimeType) GetDurationType() (*DurationType, error) {
   252  	value, err := a.GetTimeDuration()
   253  	if err != nil {
   254  		return nil, err
   255  	}
   256  
   257  	return NewDurationType(value), nil
   258  }
   259  
   260  func (a *AbsoluteOrRelativeTimeType) GetTimeDuration() (time.Duration, error) {
   261  	return getTimeDurationFromString(string(*a))
   262  }
   263  
   264  // ScaledNumberType
   265  
   266  func (m *ScaledNumberType) GetValue() float64 {
   267  	if m.Number == nil {
   268  		return 0
   269  	}
   270  	var scale float64 = 0
   271  	if m.Scale != nil {
   272  		scale = float64(*m.Scale)
   273  	}
   274  	return float64(*m.Number) * math.Pow(10, scale)
   275  }
   276  
   277  func NewScaledNumberType(value float64) *ScaledNumberType {
   278  	m := &ScaledNumberType{}
   279  
   280  	numberOfDecimals := 0
   281  	temp := strconv.FormatFloat(value, 'f', -1, 64)
   282  	index := strings.IndexByte(temp, '.')
   283  	if index > -1 {
   284  		numberOfDecimals = len(temp) - index - 1
   285  	}
   286  
   287  	// We limit this to 4 digits for now
   288  	if numberOfDecimals > 4 {
   289  		numberOfDecimals = 4
   290  	}
   291  
   292  	numberValue := NumberType(math.Trunc(value * math.Pow(10, float64(numberOfDecimals))))
   293  	m.Number = &numberValue
   294  
   295  	var scaleValue ScaleType
   296  	if numberValue != 0 {
   297  		scaleValue = ScaleType(-numberOfDecimals)
   298  	} else {
   299  		scaleValue = ScaleType(0)
   300  	}
   301  	m.Scale = &scaleValue
   302  
   303  	return m
   304  }
   305  
   306  // DeviceAddressType
   307  
   308  var _ UpdateHelper = (*DeviceAddressType)(nil)
   309  
   310  func (r *DeviceAddressType) String() string {
   311  	if r == nil {
   312  		return ""
   313  	}
   314  
   315  	var result = ""
   316  	if r.Device != nil {
   317  		result += string(*r.Device)
   318  	}
   319  
   320  	return result
   321  }
   322  
   323  // EntityAddressType
   324  
   325  var _ UpdateHelper = (*EntityAddressType)(nil)
   326  
   327  func (r *EntityAddressType) String() string {
   328  	if r == nil {
   329  		return ""
   330  	}
   331  
   332  	var result = ""
   333  	if r.Device != nil {
   334  		result += string(*r.Device)
   335  	}
   336  	result += ":["
   337  	for index, id := range r.Entity {
   338  		if index > 0 {
   339  			result += ","
   340  		}
   341  		result += fmt.Sprintf("%d", id)
   342  	}
   343  	result += "]:"
   344  	return result
   345  }
   346  
   347  // FeatureAddressType
   348  
   349  var _ UpdateHelper = (*FeatureAddressType)(nil)
   350  
   351  func (r *FeatureAddressType) String() string {
   352  	if r == nil {
   353  		return ""
   354  	}
   355  
   356  	var result = ""
   357  	if r.Device != nil {
   358  		result += string(*r.Device)
   359  	}
   360  	result += ":["
   361  	for index, id := range r.Entity {
   362  		if index > 0 {
   363  			result += ","
   364  		}
   365  		result += fmt.Sprintf("%d", id)
   366  	}
   367  	result += "]:"
   368  	if r.Feature != nil {
   369  		result += fmt.Sprintf("%d", *r.Feature)
   370  	}
   371  	return result
   372  }