/* |-------------------------------------------------------------------------- | Metadata |-------------------------------------------------------------------------- | | Name: | - Datetime Utility | | Purpose: | - Retrieve the current date and time from either the host system | clock or a trusted framework-managed NTP source and return the | result using a framework-supported date/time format pattern. | | Guideline: | - Use ObrimDatetime() as the primary entry point. | - Always provide a valid datetime type. | - Supported types are "local" and "trusted". | - Always provide the "format" configuration key. | - Use only framework-supported format patterns. | - Expect all successful results to be returned as strings. | - Use "local" when host system time is sufficient. | - Use "trusted" when synchronized network time is required. | - Handle both success and failure response codes. | | Example: | - ObrimDatetime( | "local", | map[string]any{ | "format": "yyyy-MM-dd", | }, | ) | | - ObrimDatetime( | "trusted", | map[string]any{ | "format": "yyyy-MM-dd HH:mm:ss z", | }, | ) | |-------------------------------------------------------------------------- */ /* |-------------------------------------------------------------------------- | Credit |-------------------------------------------------------------------------- | | Contributor: | - Rajon Ahmed | - Scionite | |-------------------------------------------------------------------------- */ package datetime import ( "encoding/binary" "fmt" "log" "net" "strconv" "time" ) const ( obrimDatetimeTypeLocal = "local" obrimDatetimeTypeTrusted = "trusted" ObrimDatetimeCodeSuccessRetrieved = "SUCCESS_DATETIME_RETRIEVED" ObrimDatetimeCodeFailedInvalidType = "FAILED_INVALID_TYPE" ObrimDatetimeCodeFailedInvalidFormat = "FAILED_INVALID_FORMAT" ObrimDatetimeCodeFailedTrustedTimeRetrieval = "FAILED_TRUSTED_TIME_RETRIEVAL" ) const obrimDatetimeTrustedNtpPool = "pool.ntp.org:123" // ObrimDatetimePayload defines the success payload structure. type ObrimDatetimePayload struct { Value string `json:"value"` } // ObrimDatetimeResponse defines the utility response structure. type ObrimDatetimeResponse struct { Status bool `json:"status"` Code string `json:"code"` Payload *ObrimDatetimePayload `json:"payload"` } // obrimDatetimePatternMap stores framework-supported format mappings. var obrimDatetimePatternMap = map[string]string{ "yyyy-MM-dd": "2006-01-02", "MMM dd, yyyy": "Jan 02, 2006", "MMMM dd, yyyy": "January 02, 2006", "EEE, MMM dd, yyyy": "Mon, Jan 02, 2006", "EEE, MMMM dd, yyyy": "Mon, January 02, 2006", "EEEE, MMM dd, yyyy": "Monday, Jan 02, 2006", "EEEE, MMMM dd, yyyy": "Monday, January 02, 2006", "HH:mm:ss": "15:04:05", "hh:mm:ss a": "03:04:05 PM", "yyyy-MM-dd HH:mm:ss": "2006-01-02 15:04:05", "yyyy-MM-dd HH:mm:ss z": "2006-01-02 15:04:05 MST", "yyyy-MM-dd'T'HH:mm:ssXXX": time.RFC3339, } // ObrimDatetime retrieves and formats current date and time. func ObrimDatetime( datetimeType string, config map[string]any, ) map[string]any { log.Println("[datetime] initialization started") format, code := obrimDatetimeValidate(datetimeType, config) if code != "" { log.Printf("[datetime] validation failed: %s", code) return obrimDatetimeResponse( false, code, "", ) } var datetimeValue time.Time var err error switch datetimeType { case obrimDatetimeTypeLocal: datetimeValue = obrimDatetimeLocal() case obrimDatetimeTypeTrusted: datetimeValue, err = obrimDatetimeTrusted() if err != nil { log.Printf( "[datetime] trusted time retrieval failed: %v", err, ) return obrimDatetimeResponse( false, ObrimDatetimeCodeFailedTrustedTimeRetrieval, "", ) } } formattedValue := obrimDatetimeFormatApply( datetimeValue, format, ) log.Println("[datetime] datetime retrieved successfully") return obrimDatetimeResponse( true, ObrimDatetimeCodeSuccessRetrieved, formattedValue, ) } // obrimDatetimeValidate validates utility inputs. func obrimDatetimeValidate( datetimeType string, config map[string]any, ) (string, string) { switch datetimeType { case obrimDatetimeTypeLocal: case obrimDatetimeTypeTrusted: default: return "", ObrimDatetimeCodeFailedInvalidType } formatValue, exists := config["format"] if !exists { return "", ObrimDatetimeCodeFailedInvalidFormat } format, ok := formatValue.(string) if !ok || format == "" { return "", ObrimDatetimeCodeFailedInvalidFormat } if !obrimDatetimePatternValidate(format) { return "", ObrimDatetimeCodeFailedInvalidFormat } return format, "" } // obrimDatetimePatternValidate validates supported patterns. func obrimDatetimePatternValidate(pattern string) bool { switch pattern { case "timestampsec": return true case "timestampmil": return true } _, exists := obrimDatetimePatternMap[pattern] return exists } // obrimDatetimePatternResolve resolves pattern mappings. func obrimDatetimePatternResolve( pattern string, ) (string, bool) { layout, exists := obrimDatetimePatternMap[pattern] return layout, exists } // obrimDatetimeFormatApply formats datetime values. func obrimDatetimeFormatApply( datetimeValue time.Time, pattern string, ) string { switch pattern { case "timestampsec": return strconv.FormatInt( datetimeValue.Unix(), 10, ) case "timestampmil": return strconv.FormatInt( datetimeValue.UnixMilli(), 10, ) } layout, _ := obrimDatetimePatternResolve(pattern) return datetimeValue.Format(layout) } // obrimDatetimeResponse builds utility responses. func obrimDatetimeResponse( status bool, code string, value string, ) map[string]any { if !status { return map[string]any{ "status": false, "code": code, "payload": nil, } } return map[string]any{ "status": true, "code": code, "payload": map[string]any{ "value": value, }, } } // obrimDatetimeLocal retrieves host system time. func obrimDatetimeLocal() time.Time { return time.Now() } // obrimDatetimeTrusted retrieves trusted NTP time. func obrimDatetimeTrusted() (time.Time, error) { return obrimDatetimeTrustedSync() } // obrimDatetimeTrustedSync synchronizes trusted time from NTP. func obrimDatetimeTrustedSync() (time.Time, error) { connection, err := net.DialTimeout( "udp", obrimDatetimeTrustedNtpPool, 5*time.Second, ) if err != nil { return time.Time{}, err } defer connection.Close() var request = make([]byte, 48) request[0] = 0x1B if _, err = connection.Write(request); err != nil { return time.Time{}, err } if err = connection.SetDeadline( time.Now().Add(5 * time.Second), ); err != nil { return time.Time{}, err } var response = make([]byte, 48) if _, err = connection.Read(response); err != nil { return time.Time{}, err } var ntpSeconds = binary.BigEndian.Uint32( response[40:44], ) var ntpFraction = binary.BigEndian.Uint32( response[44:48], ) const ntpEpochOffset = 2208988800 var unixSeconds = int64(ntpSeconds) - ntpEpochOffset var nanoseconds = (int64(ntpFraction) * 1e9) >> 32 if unixSeconds < 0 { return time.Time{}, fmt.Errorf( "invalid ntp timestamp", ) } return time.Unix( unixSeconds, nanoseconds, ).UTC(), nil }