Mercurial > gemma
view pkg/soap/xsdDateTime.go @ 5688:6281c18b109f sr-v2
Finsh serializing v2 meshes.
author | Sascha L. Teichmann <sascha.teichmann@intevation.de> |
---|---|
date | Mon, 12 Feb 2024 02:27:41 +0100 |
parents | f2b51ac3d5cf |
children |
line wrap: on
line source
// This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. package soap import ( "encoding/xml" "strings" "time" ) const ( dateLayout = "2006-01-02Z07:00" timeLayout = "15:04:05.999999999Z07:00" ) // // DateTime struct // // XSDDateTime is a type for representing xsd:datetime in Golang type XSDDateTime struct { innerTime time.Time hasTz bool } // StripTz removes TZ information from the datetime func (xdt *XSDDateTime) StripTz() { xdt.hasTz = false } // ToGoTime converts the time to time.Time by checking if a TZ is specified. // If there is a TZ, that TZ is used, otherwise local TZ is used func (xdt *XSDDateTime) ToGoTime() time.Time { if xdt.hasTz { return xdt.innerTime } return time.Date(xdt.innerTime.Year(), xdt.innerTime.Month(), xdt.innerTime.Day(), xdt.innerTime.Hour(), xdt.innerTime.Minute(), xdt.innerTime.Second(), xdt.innerTime.Nanosecond(), time.Local) } // MarshalXML implements xml.MarshalerAttr on XSDDateTime func (xdt XSDDateTime) MarshalXML(e *xml.Encoder, start xml.StartElement) error { xdtString := xdt.string() if xdtString != "" { return e.EncodeElement(xdtString, start) } return nil } // MarshalXMLAttr implements xml.MarshalerAttr on XSDDateTime func (xdt XSDDateTime) MarshalXMLAttr(name xml.Name) (xml.Attr, error) { xdtString := xdt.string() attr := xml.Attr{} if xdtString != "" { attr.Name = name attr.Value = xdtString } return attr, nil } // returns string representation and skips "zero" time values. It also checks if nanoseconds and TZ exist. func (xdt XSDDateTime) string() string { if !xdt.innerTime.IsZero() { dateTimeLayout := time.RFC3339Nano if xdt.innerTime.Nanosecond() == 0 { dateTimeLayout = time.RFC3339 } dtString := xdt.innerTime.Format(dateTimeLayout) if !xdt.hasTz { // split off time portion dateAndTime := strings.SplitN(dtString, "T", 2) toks := strings.SplitN(dateAndTime[1], "Z", 2) toks = strings.SplitN(toks[0], "+", 2) toks = strings.SplitN(toks[0], "-", 2) dtString = dateAndTime[0] + "T" + toks[0] } return dtString } return "" } // UnmarshalXML implements xml.Unmarshaler on XSDDateTime to use time.RFC3339Nano func (xdt *XSDDateTime) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { var content string err := d.DecodeElement(&content, &start) if err != nil { return err } xdt.innerTime, xdt.hasTz, err = fromString(content, time.RFC3339Nano) return err } // UnmarshalXMLAttr implements xml.UnmarshalerAttr on XSDDateTime to use time.RFC3339Nano func (xdt *XSDDateTime) UnmarshalXMLAttr(attr xml.Attr) error { var err error xdt.innerTime, xdt.hasTz, err = fromString(attr.Value, time.RFC3339Nano) return err } func fromString(content string, format string) (time.Time, bool, error) { var t time.Time if content == "" { return t, true, nil } hasTz := false if strings.Contains(content, "T") { // check if we have a time portion // split into date and time portion dateAndTime := strings.SplitN(content, "T", 2) if len(dateAndTime) > 1 { if strings.Contains(dateAndTime[1], "Z") || strings.Contains(dateAndTime[1], "+") || strings.Contains(dateAndTime[1], "-") { hasTz = true } } if !hasTz { content += "Z" } if content == "0001-01-01T00:00:00Z" { return t, true, nil } } else { // we don't see to have a time portion, check timezone if strings.Contains(content, "Z") || strings.Contains(content, ":") { hasTz = true } if !hasTz { content += "Z" } } t, err := time.Parse(format, content) return t, hasTz, err } // CreateXsdDateTime creates an object represent xsd:datetime object in Golang func CreateXsdDateTime(dt time.Time, hasTz bool) XSDDateTime { return XSDDateTime{ innerTime: dt, hasTz: hasTz, } } // XSDDate is a type for representing xsd:date in Golang type XSDDate struct { innerDate time.Time hasTz bool } // StripTz removes the TZ information from the date func (xd *XSDDate) StripTz() { xd.hasTz = false } // ToGoTime converts the date to Golang time.Time by checking if a TZ is specified. // If there is a TZ, that TZ is used, otherwise local TZ is used func (xd *XSDDate) ToGoTime() time.Time { if xd.hasTz { return xd.innerDate } return time.Date(xd.innerDate.Year(), xd.innerDate.Month(), xd.innerDate.Day(), 0, 0, 0, 0, time.Local) } // MarshalXML implementation on XSDDate func (xd XSDDate) MarshalXML(e *xml.Encoder, start xml.StartElement) error { xdtString := xd.string() if xdtString != "" { return e.EncodeElement(xdtString, start) } return nil } // MarshalXMLAttr implementation on XSDDate func (xd XSDDate) MarshalXMLAttr(name xml.Name) (xml.Attr, error) { xdString := xd.string() attr := xml.Attr{} if xdString != "" { attr.Name = name attr.Value = xdString } return attr, nil } // returns string representation and skips "zero" time values func (xd XSDDate) string() string { if !xd.innerDate.IsZero() { dateString := xd.innerDate.Format(dateLayout) // serialize with TZ if !xd.hasTz { if strings.Contains(dateString, "Z") { // UTC Tz toks := strings.SplitN(dateString, "Z", 2) dateString = toks[0] } else { // [+-]00:00 Tz, remove last 6 chars if len(dateString) > 5 { // this should always be true start := len(dateString) - 6 // locate at "-" dateString = dateString[0:start] } } } return dateString } return "" } // UnmarshalXML implements xml.Unmarshaler on XSDDate to use dateLayout func (xd *XSDDate) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { var content string err := d.DecodeElement(&content, &start) if err != nil { return err } xd.innerDate, xd.hasTz, err = fromString(content, dateLayout) return err } // UnmarshalXMLAttr implements xml.UnmarshalerAttr on XSDDate to use dateLayout func (xd *XSDDate) UnmarshalXMLAttr(attr xml.Attr) error { var err error xd.innerDate, xd.hasTz, err = fromString(attr.Value, dateLayout) return err } // CreateXsdDate creates an object represent xsd:datetime object in Golang func CreateXsdDate(date time.Time, hasTz bool) XSDDate { return XSDDate{ innerDate: date, hasTz: hasTz, } } // XSDTime is a type for representing xsd:time type XSDTime struct { innerTime time.Time hasTz bool } // MarshalXML implements xml.Marshaler on XSDTime func (xt XSDTime) MarshalXML(e *xml.Encoder, start xml.StartElement) error { xdtString := xt.string() if xdtString != "" { return e.EncodeElement(xdtString, start) } return nil } // MarshalXMLAttr implements xml.MarshalerAttr on XSDTime func (xt XSDTime) MarshalXMLAttr(name xml.Name) (xml.Attr, error) { xdString := xt.string() attr := xml.Attr{} if xdString != "" { attr.Name = name attr.Value = xdString } return attr, nil } // returns string representation and skips "zero" time values func (xt XSDTime) string() string { if !xt.innerTime.IsZero() { dateTimeLayout := time.RFC3339Nano if xt.innerTime.Nanosecond() == 0 { dateTimeLayout = time.RFC3339 } // split off date portion dateAndTime := strings.SplitN(xt.innerTime.Format(dateTimeLayout), "T", 2) timeString := dateAndTime[1] if !xt.hasTz { toks := strings.SplitN(timeString, "Z", 2) toks = strings.SplitN(toks[0], "+", 2) toks = strings.SplitN(toks[0], "-", 2) timeString = toks[0] } return timeString } return "" } // UnmarshalXML implements xml.Unmarshaler on XSDTime to use dateTimeLayout func (xt *XSDTime) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { var err error var content string err = d.DecodeElement(&content, &start) if err != nil { return err } return xt.fromString(content) } // UnmarshalXMLAttr implements xml.UnmarshalerAttr on XSDTime to use dateTimeLayout func (xt *XSDTime) UnmarshalXMLAttr(attr xml.Attr) error { return xt.fromString(attr.Value) } func (xt *XSDTime) fromString(content string) error { var t time.Time var err error if content == "" { xt.innerTime = t return nil } xt.hasTz = false if strings.Contains(content, "Z") || strings.Contains(content, "+") || strings.Contains(content, "-") { xt.hasTz = true } if !xt.hasTz { content += "Z" } xt.innerTime, err = time.Parse(timeLayout, content) return err } // Hour returns hour of the xsd:time func (xt XSDTime) Hour() int { return xt.innerTime.Hour() } // Minute returns minutes of the xsd:time func (xt XSDTime) Minute() int { return xt.innerTime.Minute() } // Second returns seconds of the xsd:time func (xt XSDTime) Second() int { return xt.innerTime.Second() } // Nanosecond returns nanosecond of the xsd:time func (xt XSDTime) Nanosecond() int { return xt.innerTime.Nanosecond() } // Location returns the TZ information of the xsd:time func (xt XSDTime) Location() *time.Location { if xt.hasTz { return xt.innerTime.Location() } return nil } // CreateXsdTime creates an object representing xsd:time in Golang func CreateXsdTime(hour int, min int, sec int, nsec int, loc *time.Location) XSDTime { realLoc := loc if loc == nil { realLoc = time.Local } return XSDTime{ innerTime: time.Date(1951, 10, 22, hour, min, sec, nsec, realLoc), hasTz: loc != nil, } }