blob: c83decbfd657fdcf37dc0e4db5cac4e0a63c5251 [file] [log] [blame]
// Licensed to Apache Software Foundation (ASF) under one or more contributor
// license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright
// ownership. Apache Software Foundation (ASF) licenses this file to you under
// the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package timestamp
import (
"math"
"time"
// link runtime pkg fastrand
_ "unsafe"
"github.com/pkg/errors"
"google.golang.org/protobuf/types/known/timestamppb"
modelv1 "github.com/apache/skywalking-banyandb/api/proto/banyandb/model/v1"
)
var (
maxNanoSecond = uint32(time.Millisecond - 1)
mSecond = int64(time.Millisecond)
)
// FastRandN is a fast thread local random function.
//
//go:linkname fastRandN runtime.fastrandn
func fastRandN(n uint32) uint32
// MToN convert time unix millisends to nanoseconds
func MToN(ms time.Time) time.Time {
ns := ms.UnixNano()
if ms.Nanosecond()%int(mSecond) > 0 {
ns = ns / mSecond * mSecond
}
nns := ns + int64(fastRandN(maxNanoSecond))
return time.Unix(ms.Unix(), nns%int64(time.Second))
}
// NowMilli returns a time based on a unix millisecond
func NowMilli() time.Time {
return time.UnixMilli(time.Now().UnixMilli())
}
const (
// MinNanoTime is the minimum time that can be represented.
//
// 1677-09-21 00:12:43.145224192 +0000 UTC
MinNanoTime = int64(math.MinInt64)
// MaxNanoTime is the maximum time that can be represented.
//
// 2262-04-11 23:47:16.854775807 +0000 UTC
MaxNanoTime = int64(math.MaxInt64)
)
var (
minNanoTime = time.Unix(0, MinNanoTime).UTC()
maxNanoTime = time.Unix(0, MaxNanoTime).UTC()
MaxMilliTime = time.UnixMilli(maxNanoTime.UnixMilli())
MaxMilliPbTime = timestamppb.New(MaxMilliTime)
DefaultBeginPbTime = timestamppb.New(time.Unix(0, 0))
DefaultTimeRange = &modelv1.TimeRange{
Begin: DefaultBeginPbTime,
End: MaxMilliPbTime,
}
ErrTimeOutOfRange = errors.Errorf("time is out of range %d - %d", MinNanoTime, MaxNanoTime)
ErrTimeNotMillisecond = errors.Errorf("time is not millisecond precision")
ErrTimeEmpty = errors.Errorf("time is empty")
)
// Check checks that a time is valid
func Check(t time.Time) error {
if t.Before(minNanoTime) || t.After(maxNanoTime) {
return ErrTimeOutOfRange
}
if t.Nanosecond()%int(mSecond) > 0 {
return ErrTimeNotMillisecond
}
return nil
}
// CheckPb checks that a protobuf timestamp is valid
func CheckPb(t *timestamppb.Timestamp) error {
if t == nil {
return ErrTimeEmpty
}
return Check(t.AsTime())
}
// CheckTimeRange checks that a protobuf time range is valid
func CheckTimeRange(timeRange *modelv1.TimeRange) error {
if timeRange == nil {
return ErrTimeEmpty
}
err := CheckPb(timeRange.Begin)
if err != nil {
return err
}
return CheckPb(timeRange.End)
}