From 5839cc930c8533bd0edd02e2f24f9b351d597cd1 Mon Sep 17 00:00:00 2001 From: "thanh.pham1003" Date: Wed, 21 May 2025 16:36:47 +0700 Subject: [PATCH] Add utc_timestamp tag for time.Time in UTC, fixes #60 --- datetime.go | 22 ++++++++ datetime_test.go | 24 ++++++++ example_single_fake_data_test.go | 23 ++++---- example_with_tags_test.go | 2 + faker.go | 5 +- faker_test.go | 94 ++++++++++++++++---------------- go.mod | 4 +- 7 files changed, 115 insertions(+), 59 deletions(-) diff --git a/datetime.go b/datetime.go index e71d334..c9fedb0 100644 --- a/datetime.go +++ b/datetime.go @@ -617,6 +617,7 @@ type DateTimer interface { Century(v reflect.Value) (interface{}, error) TimeZone(v reflect.Value) (interface{}, error) TimePeriod(v reflect.Value) (interface{}, error) + UTCTimestampValue(v reflect.Value) (interface{}, error) } // GetDateTimer returns a new DateTimer interface of DateTime @@ -828,3 +829,24 @@ func Timeperiod(opts ...options.OptionFunc) string { func RandomUnixTime() int64 { return rand.Int63n(time.Now().Unix()) } + +// UTCTimestamp generates a random time.Time in UTC +func (d DateTime) UTCTimestamp() time.Time { + return time.Unix(RandomUnixTime(), 0).UTC() +} + +// UTCTimestamp handles time.Time fields for utc_timestamp tag +func (d DateTime) UTCTimestampValue(v reflect.Value) (interface{}, error) { + if v.Type() != reflect.TypeOf(time.Time{}) { + return nil, fmt.Errorf("UTCTimestamp only supports time.Time, got %v", v.Type()) + } + return d.UTCTimestamp(), nil +} + +// UTCTimestamp generates a random UTC timestamp for a struct field +func UTCTimestamp(opts ...options.OptionFunc) time.Time { + return singleFakeData(UTCTimestampTag, func() interface{} { + datetime := DateTime{} + return datetime.UTCTimestamp() + }, opts...).(time.Time) +} diff --git a/datetime_test.go b/datetime_test.go index 6df0d84..d0ba4dd 100644 --- a/datetime_test.go +++ b/datetime_test.go @@ -254,3 +254,27 @@ func TestFakeTimePeriod(t *testing.T) { t.Error("function TimePeriod need return valid period") } } + +func TestUTCTimestampValueValid(t *testing.T) { + d := GetDateTimer() + var ref = struct { + some time.Time + }{ + some: time.Time{}, + } + val, err := d.UTCTimestampValue(reflect.ValueOf(&ref.some).Elem()) + if err != nil { + t.Error("function UTCTimestampValue need return valid value") + } + + result, ok := val.(time.Time) + if !ok { + t.Error("UTCTimestampValue should return time.Time") + } + if result.Location() != time.UTC { + t.Error("UTCTimestampValue should return time in UTC") + } + if time.Now().Unix() <= result.Unix() { + t.Error("UTCTimestamp should return time <= now") + } +} diff --git a/example_single_fake_data_test.go b/example_single_fake_data_test.go index 09f257f..9e469cc 100644 --- a/example_single_fake_data_test.go +++ b/example_single_fake_data_test.go @@ -15,17 +15,18 @@ func Example_singleFakeData() { fmt.Println(faker.GetRealAddress()) // => {2755 Country Drive Fremont CA 94536 {37.557882 -121.986823}} // Datetime - fmt.Println(faker.UnixTime()) // => 1197930901 - fmt.Println(faker.Date()) // => 1982-02-27 - fmt.Println(faker.TimeString()) // => 03:10:25 - fmt.Println(faker.MonthName()) // => February - fmt.Println(faker.YearString()) // => 1994 - fmt.Println(faker.DayOfWeek()) // => Sunday - fmt.Println(faker.DayOfMonth()) // => 20 - fmt.Println(faker.Timestamp()) // => 1973-06-21 14:50:46 - fmt.Println(faker.Century()) // => IV - fmt.Println(faker.Timezone()) // => Asia/Jakarta - fmt.Println(faker.Timeperiod()) // => PM + fmt.Println(faker.UnixTime()) // => 1197930901 + fmt.Println(faker.Date()) // => 1982-02-27 + fmt.Println(faker.TimeString()) // => 03:10:25 + fmt.Println(faker.MonthName()) // => February + fmt.Println(faker.YearString()) // => 1994 + fmt.Println(faker.DayOfWeek()) // => Sunday + fmt.Println(faker.DayOfMonth()) // => 20 + fmt.Println(faker.Timestamp()) // => 1973-06-21 14:50:46 + fmt.Println(faker.Century()) // => IV + fmt.Println(faker.Timezone()) // => Asia/Jakarta + fmt.Println(faker.Timeperiod()) // => PM + fmt.Println(faker.UTCTimestamp()) // => 2025-04-15 12:34:56 +0000 UTC. // Internet fmt.Println(faker.Email()) // => mJBJtbv@OSAaT.com diff --git a/example_with_tags_test.go b/example_with_tags_test.go index d26b804..63d6e2a 100644 --- a/example_with_tags_test.go +++ b/example_with_tags_test.go @@ -2,6 +2,7 @@ package faker_test import ( "fmt" + "time" "github.com/go-faker/faker/v4" ) @@ -66,6 +67,7 @@ type SomeStructWithTags struct { NumU8 uint8 `faker:"oneof: 15, 16"` NumU uint `faker:"oneof: 17, 18"` PtrNumU *uint `faker:"oneof: 19, 20"` + UTCTime time.Time `faker:"utc_timestamp"` } func Example_withTags() { diff --git a/faker.go b/faker.go index 720ddaa..b5bf543 100644 --- a/faker.go +++ b/faker.go @@ -74,6 +74,7 @@ const ( CENTURY = "century" TIMEZONE = "timezone" TimePeriodTag = "time_period" + UTCTimestampTag = "utc_timestamp" WORD = "word" SENTENCE = "sentence" PARAGRAPH = "paragraph" @@ -104,7 +105,7 @@ var PriorityTags = []string{ID, HyphenatedID, EmailTag, MacAddressTag, DomainNam IPV6Tag, PASSWORD, JWT, CountryInfoTag, LATITUDE, LONGITUDE, CreditCardNumber, CreditCardType, PhoneNumber, TollFreeNumber, E164PhoneNumberTag, TitleMaleTag, TitleFemaleTag, FirstNameTag, FirstNameMaleTag, FirstNameFemaleTag, LastNameTag, NAME, ChineseFirstNameTag, ChineseLastNameTag, ChineseNameTag, GENDER, UnixTimeTag, DATE, TIME, MonthNameTag, - YEAR, DayOfWeekTag, DayOfMonthTag, TIMESTAMP, CENTURY, TIMEZONE, TimePeriodTag, WORD, SENTENCE, PARAGRAPH, + YEAR, DayOfWeekTag, DayOfMonthTag, TIMESTAMP, CENTURY, TIMEZONE, TimePeriodTag, UTCTimestampTag, WORD, SENTENCE, PARAGRAPH, CurrencyTag, AmountTag, AmountWithCurrencyTag, SKIP, Length, SliceLength, Language, BoundaryStart, BoundaryEnd, ONEOF, BloodTypeTag, UserAgentTag, } @@ -177,6 +178,7 @@ func initDefaultTag() { defaultTag.Store(CENTURY, CENTURY) defaultTag.Store(TIMEZONE, TIMEZONE) defaultTag.Store(TimePeriodTag, TimePeriodFormat) + defaultTag.Store(UTCTimestampTag, UTCTimestampTag) defaultTag.Store(WORD, WORD) defaultTag.Store(SENTENCE, SENTENCE) defaultTag.Store(PARAGRAPH, PARAGRAPH) @@ -226,6 +228,7 @@ func initMapperTagDefault() { mapperTag.Store(CENTURY, GetDateTimer().Century) mapperTag.Store(TIMEZONE, GetDateTimer().TimeZone) mapperTag.Store(TimePeriodTag, GetDateTimer().TimePeriod) + mapperTag.Store(UTCTimestampTag, GetDateTimer().UTCTimestampValue) mapperTag.Store(WORD, GetLorem().Word) mapperTag.Store(SENTENCE, GetLorem().Sentence) mapperTag.Store(PARAGRAPH, GetLorem().Paragraph) diff --git a/faker_test.go b/faker_test.go index aac7c7e..3d95d12 100644 --- a/faker_test.go +++ b/faker_test.go @@ -255,51 +255,52 @@ type CStruct struct { } type TaggedStruct struct { - Latitude float32 `faker:"lat" custom_tag_name:"lat" ` - Longitude float32 `faker:"long" custom_tag_name:"long"` - CreditCardNumber string `faker:"cc_number" custom_tag_name:"cc_number"` - CreditCardType string `faker:"cc_type" custom_tag_name:"cc_type"` - Email string `faker:"email" custom_tag_name:"email"` - DomainName string `faker:"domain_name" custom_tag_name:"domain_name"` - IPV4 string `faker:"ipv4" custom_tag_name:"ipv4"` - IPV6 string `faker:"ipv6" custom_tag_name:"ipv6"` - Password string `faker:"password" custom_tag_name:"password"` - Jwt string `faker:"jwt" custom_tag_name:"jwt"` - PhoneNumber string `faker:"phone_number" custom_tag_name:"phone_number"` - MacAddress string `faker:"mac_address" custom_tag_name:"mac_address"` - URL string `faker:"url" custom_tag_name:"url"` - UserName string `faker:"username" custom_tag_name:"username"` - TollFreeNumber string `faker:"toll_free_number" custom_tag_name:"toll_free_number"` - E164PhoneNumber string `faker:"e_164_phone_number" custom_tag_name:"e_164_phone_number"` - TitleMale string `faker:"title_male" custom_tag_name:"title_male"` - TitleFemale string `faker:"title_female" custom_tag_name:"title_female"` - FirstName string `faker:"first_name" custom_tag_name:"first_name"` - FirstNameMale string `faker:"first_name_male" custom_tag_name:"first_name_male"` - FirstNameFemale string `faker:"first_name_female" custom_tag_name:"first_name_female"` - LastName string `faker:"last_name" custom_tag_name:"last_name"` - Name string `faker:"name" custom_tag_name:"name"` - ChineseFirstName string `faker:"chinese_first_name" custom_tag_name:"chinese_first_name"` - ChineseLastName string `faker:"chinese_last_name" custom_tag_name:"chinese_last_name"` - ChineseName string `faker:"chinese_name" custom_tag_name:"chinese_name"` - UnixTime int64 `faker:"unix_time" custom_tag_name:"unix_time"` - Date string `faker:"date" custom_tag_name:"date"` - Time string `faker:"time" custom_tag_name:"time"` - MonthName string `faker:"month_name" custom_tag_name:"month_name"` - Year string `faker:"year" custom_tag_name:"year"` - DayOfWeek string `faker:"day_of_week" custom_tag_name:"day_of_week"` - DayOfMonth string `faker:"day_of_month" custom_tag_name:"day_of_month"` - Timestamp string `faker:"timestamp" custom_tag_name:"timestamp"` - Century string `faker:"century" custom_tag_name:"century"` - TimeZone string `faker:"timezone" custom_tag_name:"timezone"` - TimePeriod string `faker:"time_period" custom_tag_name:"time_period"` - Word string `faker:"word" custom_tag_name:"word"` - Sentence string `faker:"sentence" custom_tag_name:"sentence"` - Paragraph string `faker:"paragraph" custom_tag_name:"paragraph"` - Currency string `faker:"currency" custom_tag_name:"currency"` - Amount float32 `faker:"amount" custom_tag_name:"amount"` - AmountWithCurrency string `faker:"amount_with_currency" custom_tag_name:"amount_with_currency"` - ID string `faker:"uuid_digit" custom_tag_name:"uuid_digit"` - HyphenatedID string `faker:"uuid_hyphenated" custom_tag_name:"uuid_hyphenated"` + Latitude float32 `faker:"lat" custom_tag_name:"lat" ` + Longitude float32 `faker:"long" custom_tag_name:"long"` + CreditCardNumber string `faker:"cc_number" custom_tag_name:"cc_number"` + CreditCardType string `faker:"cc_type" custom_tag_name:"cc_type"` + Email string `faker:"email" custom_tag_name:"email"` + DomainName string `faker:"domain_name" custom_tag_name:"domain_name"` + IPV4 string `faker:"ipv4" custom_tag_name:"ipv4"` + IPV6 string `faker:"ipv6" custom_tag_name:"ipv6"` + Password string `faker:"password" custom_tag_name:"password"` + Jwt string `faker:"jwt" custom_tag_name:"jwt"` + PhoneNumber string `faker:"phone_number" custom_tag_name:"phone_number"` + MacAddress string `faker:"mac_address" custom_tag_name:"mac_address"` + URL string `faker:"url" custom_tag_name:"url"` + UserName string `faker:"username" custom_tag_name:"username"` + TollFreeNumber string `faker:"toll_free_number" custom_tag_name:"toll_free_number"` + E164PhoneNumber string `faker:"e_164_phone_number" custom_tag_name:"e_164_phone_number"` + TitleMale string `faker:"title_male" custom_tag_name:"title_male"` + TitleFemale string `faker:"title_female" custom_tag_name:"title_female"` + FirstName string `faker:"first_name" custom_tag_name:"first_name"` + FirstNameMale string `faker:"first_name_male" custom_tag_name:"first_name_male"` + FirstNameFemale string `faker:"first_name_female" custom_tag_name:"first_name_female"` + LastName string `faker:"last_name" custom_tag_name:"last_name"` + Name string `faker:"name" custom_tag_name:"name"` + ChineseFirstName string `faker:"chinese_first_name" custom_tag_name:"chinese_first_name"` + ChineseLastName string `faker:"chinese_last_name" custom_tag_name:"chinese_last_name"` + ChineseName string `faker:"chinese_name" custom_tag_name:"chinese_name"` + UnixTime int64 `faker:"unix_time" custom_tag_name:"unix_time"` + Date string `faker:"date" custom_tag_name:"date"` + Time string `faker:"time" custom_tag_name:"time"` + MonthName string `faker:"month_name" custom_tag_name:"month_name"` + Year string `faker:"year" custom_tag_name:"year"` + DayOfWeek string `faker:"day_of_week" custom_tag_name:"day_of_week"` + DayOfMonth string `faker:"day_of_month" custom_tag_name:"day_of_month"` + Timestamp string `faker:"timestamp" custom_tag_name:"timestamp"` + Century string `faker:"century" custom_tag_name:"century"` + TimeZone string `faker:"timezone" custom_tag_name:"timezone"` + TimePeriod string `faker:"time_period" custom_tag_name:"time_period"` + Word string `faker:"word" custom_tag_name:"word"` + Sentence string `faker:"sentence" custom_tag_name:"sentence"` + Paragraph string `faker:"paragraph" custom_tag_name:"paragraph"` + Currency string `faker:"currency" custom_tag_name:"currency"` + Amount float32 `faker:"amount" custom_tag_name:"amount"` + AmountWithCurrency string `faker:"amount_with_currency" custom_tag_name:"amount_with_currency"` + ID string `faker:"uuid_digit" custom_tag_name:"uuid_digit"` + HyphenatedID string `faker:"uuid_hyphenated" custom_tag_name:"uuid_hyphenated"` + UTCTimestamp time.Time `faker:"utc_timestamp" custom_tag_name:"utc_timestamp"` } func (t TaggedStruct) String() string { @@ -346,6 +347,7 @@ func (t TaggedStruct) String() string { AmountWithCurrency: %s, HyphenatedID: %s, ID: %s, + UTCTimestamp: %v, }`, t.Latitude, t.Longitude, t.CreditCardNumber, t.CreditCardType, t.Email, t.DomainName, t.IPV4, t.IPV6, t.Password, t.Jwt, t.PhoneNumber, t.MacAddress, @@ -357,7 +359,7 @@ func (t TaggedStruct) String() string { t.DayOfMonth, t.Timestamp, t.Century, t.TimeZone, t.TimePeriod, t.Word, t.Sentence, t.Paragraph, t.Currency, t.Amount, t.AmountWithCurrency, - t.HyphenatedID, t.ID, + t.HyphenatedID, t.ID, t.UTCTimestamp, ) } diff --git a/go.mod b/go.mod index 4f2cead..89fcb4b 100644 --- a/go.mod +++ b/go.mod @@ -1,5 +1,7 @@ module github.com/go-faker/faker/v4 -go 1.18 +go 1.23.0 + +toolchain go1.23.5 require golang.org/x/text v0.24.0