master
go 114 lines 3.9 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 //go:build linux && cgo && ibm_mq
4
5 package pcf
6
7 import (
8 "fmt"
9 "strconv"
10 "strings"
11 "time"
12 )
13
14 // ParseMQDateTime parses IBM MQ date and time strings into time.Time
15 // Supports both old format (YYYYMMDD, HHMMSSSS) and new format (YYYY-MM-DD, HH:MM:SS or HH.MM.SS)
16 //
17 // CRITICAL: Based on real-world testing, ALL IBM MQ PCF timestamps appear to be UTC:
18 // - Message timestamps (MQMD PutDate/PutTime): Always UTC
19 // - Administrative timestamps (start times, alteration times): Also UTC (contrary to some documentation)
20 //
21 // Parameters:
22 //
23 // date: Date string in format YYYYMMDD or YYYY-MM-DD
24 // timeStr: Time string in format HHMMSSSS or HH:MM:SS or HH.MM.SS
25 // isUTC: true for UTC timestamps, false for local time (kept for compatibility)
26 func ParseMQDateTime(date, timeStr string, isUTC bool) (time.Time, error) {
27 if date == "" || timeStr == "" {
28 return time.Time{}, fmt.Errorf("empty date or time")
29 }
30
31 var parsedTime time.Time
32 var err error
33 var timezone *time.Location
34
35 // Set timezone based on timestamp type
36 if isUTC {
37 timezone = time.UTC
38 } else {
39 timezone = time.Local // Use system local time (queue manager timezone)
40 }
41
42 // Try new format first: "YYYY-MM-DD" + "HH:MM:SS" or "HH.MM.SS"
43 if len(date) == 10 && date[4] == '-' {
44 // New format: "2024-01-15" + "14:30:25" or "14.30.25"
45 // Replace dots with colons if present
46 cleanTimeStr := strings.ReplaceAll(timeStr, ".", ":")
47 datetime := date + "T" + cleanTimeStr
48
49 if isUTC {
50 datetime += "Z" // Add UTC suffix for message timestamps
51 parsedTime, err = time.Parse("2006-01-02T15:04:05Z", datetime)
52 } else {
53 // Parse in local timezone for administrative timestamps
54 parsedTime, err = time.ParseInLocation("2006-01-02T15:04:05", datetime, timezone)
55 }
56
57 if err != nil {
58 return time.Time{}, fmt.Errorf("failed to parse new format date/time %s + %s (UTC=%v): %v", date, timeStr, isUTC, err)
59 }
60 } else {
61 // Try old format: "YYYYMMDD" + "HHMMSSSS"
62 if len(date) != 8 {
63 return time.Time{}, fmt.Errorf("invalid date format: %s (expected YYYYMMDD or YYYY-MM-DD)", date)
64 }
65 if len(timeStr) != 8 {
66 return time.Time{}, fmt.Errorf("invalid time format: %s (expected HHMMSSSS or HH:MM:SS)", timeStr)
67 }
68
69 // Parse YYYYMMDD
70 year, _ := strconv.Atoi(date[0:4])
71 month, _ := strconv.Atoi(date[4:6])
72 day, _ := strconv.Atoi(date[6:8])
73
74 // Parse HHMMSSSS (HH MM SS SS where last SS is centiseconds)
75 hour, _ := strconv.Atoi(timeStr[0:2])
76 minute, _ := strconv.Atoi(timeStr[2:4])
77 second, _ := strconv.Atoi(timeStr[4:6])
78 // Ignore centiseconds for uptime calculation
79
80 parsedTime = time.Date(year, time.Month(month), day, hour, minute, second, 0, timezone)
81 }
82
83 return parsedTime, nil
84 }
85
86 // ParseMQMessageDateTime parses IBM MQ message timestamps (always UTC)
87 // Used for MQMD PutDate/PutTime and other message-related timestamps
88 func ParseMQMessageDateTime(date, timeStr string) (time.Time, error) {
89 return ParseMQDateTime(date, timeStr, true) // Message timestamps are UTC
90 }
91
92 // ParseMQAdminDateTime parses IBM MQ administrative timestamps (UTC)
93 // CORRECTION: Based on real-world testing, ALL IBM MQ PCF timestamps appear to be UTC
94 // Used for queue manager start times, listener start times, object alteration times
95 func ParseMQAdminDateTime(date, timeStr string) (time.Time, error) {
96 return ParseMQDateTime(date, timeStr, true) // ALL PCF timestamps are UTC
97 }
98
99 // CalculateUptimeSeconds calculates uptime in seconds from IBM MQ administrative start date and time
100 // CORRECTION: Based on real-world testing, administrative timestamps are actually UTC
101 func CalculateUptimeSeconds(startDate, startTime string) (int64, error) {
102 parsedTime, err := ParseMQAdminDateTime(startDate, startTime)
103 if err != nil {
104 return 0, err
105 }
106
107 // Calculate uptime as seconds since start time
108 uptime := time.Since(parsedTime)
109 if uptime < 0 {
110 return 0, fmt.Errorf("start time is in the future: %v", parsedTime)
111 }
112
113 return int64(uptime.Seconds()), nil
114 }