Documentation
¶
Overview ¶
Package timestamp provides standardized Unix timestamp handling utilities.
Overview ¶
The timestamp package establishes int64 milliseconds as the canonical timestamp format throughout the codebase. This eliminates common timestamp parsing bugs and provides consistent behavior across all components.
Design decisions:
- All timestamps are Unix milliseconds (ms since epoch, UTC)
- Zero value (0) means "not set" or "unknown"
- Functions handle zero values gracefully
- Automatic detection of seconds vs milliseconds input
Why Milliseconds? ¶
Milliseconds provide sufficient precision for most applications while avoiding the complexity of nanoseconds. They map naturally to JavaScript Date.now() and most database timestamp columns.
Zero Value Semantics ¶
A timestamp of 0 is treated as "unset":
timestamp.Format(0) // Returns ""
timestamp.FromUnixMs(0) // Returns time.Time{} (zero time)
timestamp.Since(0) // Returns 0
timestamp.Min(0, ts) // Returns ts (0 treated as "later")
This allows timestamp fields to be optional without using pointers.
Usage ¶
Getting current time:
now := timestamp.Now() // Returns current Unix milliseconds
Converting between types:
// time.Time → int64 ts := timestamp.ToUnixMs(time.Now()) // int64 → time.Time t := timestamp.FromUnixMs(ts) t := timestamp.ToTime(ts) // Alias for readability
Formatting for display:
s := timestamp.Format(ts) // Returns "2024-01-15T10:30:00Z"
Parsing various inputs:
// RFC3339 string
ts := timestamp.Parse("2024-01-15T10:30:00Z")
// Unix seconds (auto-detected)
ts := timestamp.Parse(1705315800)
// Unix milliseconds (auto-detected)
ts := timestamp.Parse(1705315800000)
// time.Time
ts := timestamp.Parse(time.Now())
Time arithmetic:
// Add duration future := timestamp.Add(ts, 1*time.Hour) // Subtract duration past := timestamp.Sub(ts, 30*time.Minute) // Duration between timestamps elapsed := timestamp.Between(start, end) // Duration since timestamp age := timestamp.Since(ts)
Comparison:
earlier := timestamp.Min(ts1, ts2) later := timestamp.Max(ts1, ts2) timestamp.IsZero(ts) // true if 0
Validation:
if err := timestamp.Validate(ts); err != nil {
// Invalid: negative or unreasonably far in future
}
Migration Guide ¶
Replace common patterns:
// Old: time.Now().Unix() // New: now := timestamp.Now() // Old: time.Unix(sec, 0) // New: t := timestamp.FromUnixMs(sec * 1000) // Old: time.Parse(time.RFC3339, s) // New: ts := timestamp.Parse(s) // Old: t.Format(time.RFC3339) // New: s := timestamp.Format(ts)
Auto-Detection Logic ¶
Parse() automatically detects seconds vs milliseconds:
- Values > 1e12 (year ~2001 in ms) are treated as milliseconds
- Values ≤ 1e12 are treated as seconds and converted
This handles both JavaScript (milliseconds) and Unix (seconds) conventions.
Thread Safety ¶
All functions are pure (no shared state) and safe for concurrent use.
See Also ¶
Related packages:
- time: Go standard library time package
- github.com/c360studio/semstreams/graph: Uses int64 timestamps for EntityState
Package timestamp provides standardized Unix timestamp handling utilities.
This package uses int64 milliseconds as the canonical timestamp format to eliminate timestamp parsing bugs and provide consistent behavior across the codebase. All timestamps are stored as milliseconds since Unix epoch (UTC).
Zero Value Semantics:
- A timestamp value of 0 means "not set" or "unknown"
- Functions handle zero values gracefully, returning appropriate defaults
Migration Guide:
- Replace time.Now().Unix() with timestamp.Now()
- Replace time.Unix(sec, 0) with timestamp.FromUnixMs(sec * 1000)
- Replace RFC3339 string parsing with timestamp.Parse()
Usage Examples:
// Current time
now := timestamp.Now()
// Convert from time.Time
t := time.Now()
ts := timestamp.ToUnixMs(t)
// Convert to time.Time
t := timestamp.FromUnixMs(ts)
// Format for display
display := timestamp.Format(ts)
// Parse various formats
ts := timestamp.Parse("2023-01-01T12:00:00Z")
ts := timestamp.Parse(1672574400000)
Index ¶
- func Add(ms int64, d time.Duration) int64
- func Between(start, end int64) time.Duration
- func Format(ms int64) string
- func FromUnixMs(ms int64) time.Time
- func IsZero(ms int64) bool
- func Max(a, b int64) int64
- func Min(a, b int64) int64
- func Now() int64
- func Parse(input any) int64
- func Since(ms int64) time.Duration
- func Sub(ms int64, d time.Duration) int64
- func ToTime(ms int64) time.Time
- func ToUnixMs(t time.Time) int64
- func Validate(ms int64) error
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Add ¶
Add adds a duration to a timestamp and returns the new timestamp. Returns 0 if the input timestamp is zero.
Example ¶
ExampleAdd demonstrates timestamp arithmetic
package main
import (
"fmt"
"time"
"github.com/c360studio/semstreams/pkg/timestamp"
)
func main() {
ts := int64(1673785845123)
// Add 1 hour
future := timestamp.Add(ts, time.Hour)
fmt.Printf("Original: %s\n", timestamp.Format(ts))
fmt.Printf("Plus 1 hour: %s\n", timestamp.Format(future))
// Add to zero timestamp returns zero
zero := timestamp.Add(0, time.Hour)
fmt.Printf("Add to zero: %d\n", zero)
}
Output: Original: 2023-01-15T12:30:45Z Plus 1 hour: 2023-01-15T13:30:45Z Add to zero: 0
func Between ¶
Between returns the duration between two timestamps. Returns 0 if either timestamp is zero.
Example ¶
ExampleBetween demonstrates calculating duration between timestamps
package main
import (
"fmt"
"time"
"github.com/c360studio/semstreams/pkg/timestamp"
)
func main() {
start := int64(1673785845123)
end := timestamp.Add(start, 30*time.Minute)
duration := timestamp.Between(start, end)
fmt.Printf("Duration: %v\n", duration)
// Zero timestamps return zero duration
zeroDuration := timestamp.Between(0, end)
fmt.Printf("With zero: %v\n", zeroDuration)
}
Output: Duration: 30m0s With zero: 0s
func Format ¶
Format converts Unix milliseconds to RFC3339 string for display. Returns empty string if timestamp is 0.
Example ¶
ExampleFormat demonstrates formatting timestamps for display
package main
import (
"fmt"
"github.com/c360studio/semstreams/pkg/timestamp"
)
func main() {
ts := int64(1673785845123)
formatted := timestamp.Format(ts)
fmt.Printf("Formatted: %s\n", formatted)
// Zero timestamp returns empty string
empty := timestamp.Format(0)
fmt.Printf("Zero formatted: '%s'\n", empty)
}
Output: Formatted: 2023-01-15T12:30:45Z Zero formatted: ''
func FromUnixMs ¶
FromUnixMs converts Unix milliseconds to time.Time. Returns zero time if timestamp is 0.
Example ¶
ExampleFromUnixMs demonstrates converting milliseconds to time.Time
package main
import (
"fmt"
"time"
"github.com/c360studio/semstreams/pkg/timestamp"
)
func main() {
ts := int64(1673785845123)
t := timestamp.FromUnixMs(ts)
fmt.Printf("Milliseconds to time.Time: %s\n", t.UTC().Format(time.RFC3339))
// Zero timestamp returns zero time
zeroTime := timestamp.FromUnixMs(0)
fmt.Printf("Zero timestamp: %v\n", zeroTime.IsZero())
}
Output: Milliseconds to time.Time: 2023-01-15T12:30:45Z Zero timestamp: true
func Max ¶
Max returns the later of two timestamps. Zero values are treated as "earlier than any other time".
func Min ¶
Min returns the earlier of two timestamps. Zero values are treated as "later than any other time".
func Now ¶
func Now() int64
Now returns the current time as Unix milliseconds.
Example ¶
ExampleNow demonstrates getting the current timestamp
package main
import (
"fmt"
"github.com/c360studio/semstreams/pkg/timestamp"
)
func main() {
ts := timestamp.Now()
fmt.Printf("Current timestamp: %d (milliseconds)\n", ts)
// Output would vary, so we'll just show the format
}
func Parse ¶
Parse converts various timestamp formats to Unix milliseconds. Supports:
- int64 (assumed to be milliseconds if > 1e12, otherwise seconds)
- float64 (converted to int64, same logic as int64)
- string (RFC3339 or Unix timestamp string)
- time.Time
- nil/zero values (returns 0)
Returns 0 for invalid input or parsing errors.
Example ¶
ExampleParse demonstrates parsing various timestamp formats
package main
import (
"fmt"
"github.com/c360studio/semstreams/pkg/timestamp"
)
func main() {
// Parse RFC3339 string
ts1 := timestamp.Parse("2023-01-15T12:30:45Z")
fmt.Printf("RFC3339 parsed: %d\n", ts1)
// Parse Unix seconds
ts2 := timestamp.Parse(int64(1673784645))
fmt.Printf("Unix seconds parsed: %d\n", ts2)
// Parse Unix milliseconds
ts3 := timestamp.Parse(int64(1673784645123))
fmt.Printf("Unix milliseconds parsed: %d\n", ts3)
}
Output: RFC3339 parsed: 1673785845000 Unix seconds parsed: 1673784645000 Unix milliseconds parsed: 1673784645123
func Sub ¶
Sub subtracts a duration from a timestamp and returns the new timestamp. Returns 0 if the input timestamp is zero.
func ToUnixMs ¶
ToUnixMs converts a time.Time to Unix milliseconds.
Example ¶
ExampleToUnixMs demonstrates converting time.Time to milliseconds
package main
import (
"fmt"
"time"
"github.com/c360studio/semstreams/pkg/timestamp"
)
func main() {
t := time.Date(2023, 1, 15, 12, 30, 45, 123000000, time.UTC)
ts := timestamp.ToUnixMs(t)
fmt.Printf("time.Time to milliseconds: %d\n", ts)
}
Output: time.Time to milliseconds: 1673785845123
Types ¶
This section is empty.