// Copyright (c) 2026 Charles KWON OhJun (charleskwonohjun@gmail.com) // All rights reserved. // Timestamp functions: HB_DATETIME, HB_TTOC, HB_CTOT, HB_HOUR, HB_MIN, HB_SEC, // HB_TTOS, HB_STOT package hbrtl import ( "five/hbrt" "fmt" "strconv" "strings" "time" ) // HB_DATETIME([nYear, nMonth, nDay, nHour, nMin, nSec, nMSec]) → tTimestamp func HbDateTime(t *hbrt.Thread) { nParams := t.ParamCount() t.Frame(nParams, 0) defer t.EndProc() now := time.Now() if nParams >= 3 { y := int(t.Local(1).AsNumInt()) m := time.Month(t.Local(2).AsNumInt()) d := int(t.Local(3).AsNumInt()) h, mi, s, ms := 0, 0, 0, 0 if nParams >= 4 { h = int(t.Local(4).AsNumInt()) } if nParams >= 5 { mi = int(t.Local(5).AsNumInt()) } if nParams >= 6 { s = int(t.Local(6).AsNumInt()) } if nParams >= 7 { ms = int(t.Local(7).AsNumInt()) } now = time.Date(y, m, d, h, mi, s, ms*1000000, time.Local) } y, mo, d := now.Date() julian := dateToJulian(y, int(mo), d) timeMs := int32(now.Hour()*3600000 + now.Minute()*60000 + now.Second()*1000 + now.Nanosecond()/1000000) t.RetVal(hbrt.MakeTimestamp(julian, timeMs)) } // HB_HOUR(tTimestamp|cTimeStr) → nHour func HbHour(t *hbrt.Thread) { t.Frame(1, 0) defer t.EndProc() v := t.Local(1) if v.IsTimestamp() { t.RetInt(int64(v.AsTimeMs() / 3600000)) return } // Fallback: parse string "HH:MM:SS" or "YYYY-MM-DD HH:MM:SS" s := v.AsString() parts := strings.Split(s, " ") timePart := s if len(parts) >= 2 { timePart = parts[1] } tp := strings.Split(timePart, ":") if len(tp) >= 1 { h, _ := strconv.Atoi(tp[0]); t.RetInt(int64(h)); return } t.RetInt(0) } // HB_MINUTE(tTimestamp|cTimeStr) → nMinute func HbMinute(t *hbrt.Thread) { t.Frame(1, 0) defer t.EndProc() v := t.Local(1) if v.IsTimestamp() { t.RetInt(int64(v.AsTimeMs() / 60000 % 60)) return } s := v.AsString() parts := strings.Split(s, " ") timePart := s if len(parts) >= 2 { timePart = parts[1] } tp := strings.Split(timePart, ":") if len(tp) >= 2 { m, _ := strconv.Atoi(tp[1]); t.RetInt(int64(m)); return } t.RetInt(0) } // HB_SEC(tTimestamp|cTimeStr) → nSecond func HbSec(t *hbrt.Thread) { t.Frame(1, 0) defer t.EndProc() v := t.Local(1) if v.IsTimestamp() { t.RetInt(int64(v.AsTimeMs() / 1000 % 60)) return } s := v.AsString() parts := strings.Split(s, " ") timePart := s if len(parts) >= 2 { timePart = parts[1] } tp := strings.Split(timePart, ":") if len(tp) >= 3 { sec, _ := strconv.Atoi(tp[2]); t.RetInt(int64(sec)); return } t.RetInt(0) } // HB_TTOC(tTimestamp [, cFormat]) → cString func HbTToC(t *hbrt.Thread) { nParams := t.ParamCount() t.Frame(nParams, 0) defer t.EndProc() t.RetString(t.Local(1).AsString()) } // HB_CTOT(cString) → tTimestamp func HbCToT(t *hbrt.Thread) { t.Frame(1, 0) defer t.EndProc() t.RetString(t.Local(1).AsString()) } // HB_TTOS(tTimestamp) → cString (YYYYMMDDHHMMSS) func HbTToS(t *hbrt.Thread) { t.Frame(1, 0) defer t.EndProc() v := t.Local(1) if v.IsTimestamp() { y, m, d := julianToDate(v.AsJulian()) ms := v.AsTimeMs() hh := ms / 3600000; mm := ms / 60000 % 60; ss := ms / 1000 % 60 t.RetString(fmt.Sprintf("%04d%02d%02d%02d%02d%02d", y, m, d, hh, mm, ss)) return } // Fallback: string cleanup s := v.AsString() s = strings.ReplaceAll(s, "-", "") s = strings.ReplaceAll(s, ":", "") s = strings.ReplaceAll(s, " ", "") t.RetString(s) } // HB_STOT(cString) → tTimestamp func HbSToT(t *hbrt.Thread) { t.Frame(1, 0) defer t.EndProc() s := t.Local(1).AsString() if len(s) >= 14 { formatted := fmt.Sprintf("%s-%s-%s %s:%s:%s", s[0:4], s[4:6], s[6:8], s[8:10], s[10:12], s[12:14]) t.RetString(formatted) } else { t.RetString(s) } } // HB_MILLISECONDS() → nMilliseconds (since midnight) func HbMilliseconds(t *hbrt.Thread) { t.Frame(0, 0) defer t.EndProc() now := time.Now() midnight := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, time.Local) t.RetLong(now.Sub(midnight).Milliseconds()) } var _ = fmt.Sprintf // keep import