| // 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) |
| } |