Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: date related changes for go package #199

Open
wants to merge 19 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
132 changes: 83 additions & 49 deletions packages/i18nify-go/example/example.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,63 +2,97 @@ package main

import (
"fmt"
i18nify_go "github.com/razorpay/i18nify/packages/i18nify-go"
"github.com/razorpay/i18nify/packages/i18nify-go/modules/currency"
"github.com/razorpay/i18nify/packages/i18nify-go/modules/date_time"
"time"
)

func main() {
//India
countryIN := i18nify_go.NewCountry("IN")
//countryIN := i18nify_go.NewCountry("IN")
//
//metaDataIN := countryIN.GetCountryMetadata()
//fmt.Println(metaDataIN.CountryName) //India
//fmt.Println(metaDataIN.SupportedCurrency) //[INR]
//fmt.Println(metaDataIN.DialCode) //+91
//fmt.Println(metaDataIN.Timezones) //Asia/Kolkata:{UTC +05:30}
//fmt.Println(metaDataIN.DefaultLocale) //en_IN
//
////INR
//currencyIN := countryIN.GetCountryCurrency()
//fmt.Println(currencyIN[0].Name) //Indian Rupee
//fmt.Println(currencyIN[0].Symbol) //₹
//
////India PhoneNumber
//phoneNumberIN := countryIN.GetCountryPhoneNumber()
//fmt.Println(phoneNumberIN.DialCode) //+91
//fmt.Println(phoneNumberIN.Regex) // /^(?:(?:\+|0{0,2})91\s*[-]?\s*|[0]?)?[6789]\d{9}$/
//
////India States
//subdivisions := countryIN.GetCountrySubDivisions()
//fmt.Println(subdivisions.GetCountryName()) //India
//
//state := subdivisions.GetStates()["KA"]
//fmt.Println(state.GetName()) //Karnataka
//fmt.Println(state.GetCities()[0]) //{Yellāpur nan Asia/Kolkata [581337 581337 ...}
//fmt.Println(len(state.GetCities())) //58
//
//// Get States by zipcode
//// As suggested online there are some cases in which one zipcode can be
//madhyaPradesh := countryIN.GetStatesByZipCode("452010")[0]
//fmt.Printf("For pincode 452010 state : %s\n", madhyaPradesh) // {[{Wārāseonī nan Asia/Kolkata [481331 ...}
//fmt.Printf("State name %s\n", madhyaPradesh.GetName())
//
//// Get Cities
//cityList := madhyaPradesh.Cities
//fmt.Println("Cities :")
//for _, city := range cityList {
// fmt.Println(city.Name)
//}
//
//// Get zipcodes by city
//zipcodes := countryIN.GetZipCodesFromCity("indore")
//for _, val := range zipcodes {
// fmt.Println(val)
//}
//
////USD
//currencyUS, _ := currency.GetCurrencyInformation("USD")
//fmt.Println(currencyUS.Name) //US Dollar
//fmt.Println(currencyUS.Symbol) //$

metaDataIN := countryIN.GetCountryMetadata()
fmt.Println(metaDataIN.CountryName) //India
fmt.Println(metaDataIN.SupportedCurrency) //[INR]
fmt.Println(metaDataIN.DialCode) //+91
fmt.Println(metaDataIN.Timezones) //Asia/Kolkata:{UTC +05:30}
fmt.Println(metaDataIN.DefaultLocale) //en_IN
// date_time
// get date in time format
currentDateTime, _ := date_time.StringToDate("12/12/2024") //2024-12-12 00:00:00 +0000 UTC
fmt.Println("currentDate ", currentDateTime)

//INR
currencyIN := countryIN.GetCountryCurrency()
fmt.Println(currencyIN[0].Name) //Indian Rupee
fmt.Println(currencyIN[0].Symbol) //₹
// get dateTime in specific format with Locale
date, err := date_time.FormatDateTime("2024-12-12 00:00:00 +0000 UTC", &date_time.DateTimeOptions{
DateTimeMode: date_time.DateTimeMode,
IntlOptions: &date_time.IntlOptions{
Locale: "IST",
},
})
fmt.Println("IST converted dateTime ", date, err) //12/12/2024, 05:30:00 IST
// get dateTime in specific format without Locale
date, err = date_time.FormatDateTime("2024-12-12 00:00:00 +0000 UTC", &date_time.DateTimeOptions{
DateTimeMode: date_time.DateTimeMode,
IntlOptions: &date_time.IntlOptions{},
})
fmt.Println("No Locale passed converted dateTime ", date, err) //12/12/2024, 00:00:00

//India PhoneNumber
phoneNumberIN := countryIN.GetCountryPhoneNumber()
fmt.Println(phoneNumberIN.DialCode) //+91
fmt.Println(phoneNumberIN.Regex) // /^(?:(?:\+|0{0,2})91\s*[-]?\s*|[0]?)?[6789]\d{9}$/
// get relative time
relativeDate := time.Now().Add(365 * date_time.Day).Format(time.RFC3339)
currentDate := time.Now().Format(time.RFC3339)
relativeTime, err := date_time.GetRelativeTime(relativeDate, date_time.DateTimeOptions{
BaseDate: currentDate,
})
fmt.Println("Relative time (future) - ", relativeTime, err) // in 1 Year

//India States
subdivisions := countryIN.GetCountrySubDivisions()
fmt.Println(subdivisions.GetCountryName()) //India

state := subdivisions.GetStates()["KA"]
fmt.Println(state.GetName()) //Karnataka
fmt.Println(state.GetCities()[0]) //{Yellāpur nan Asia/Kolkata [581337 581337 ...}
fmt.Println(len(state.GetCities())) //58

// Get States by zipcode
// As suggested online there are some cases in which one zipcode can be
madhyaPradesh := countryIN.GetStatesByZipCode("452010")[0]
fmt.Printf("For pincode 452010 state : %s\n", madhyaPradesh) // {[{Wārāseonī nan Asia/Kolkata [481331 ...}
fmt.Printf("State name %s\n", madhyaPradesh.GetName())

// Get Cities
cityList := madhyaPradesh.Cities
fmt.Println("Cities :")
for _, city := range cityList {
fmt.Println(city.Name)
}

// Get zipcodes by city
zipcodes := countryIN.GetZipCodesFromCity("indore")
for _, val := range zipcodes {
fmt.Println(val)
}

//USD
currencyUS, _ := currency.GetCurrencyInformation("USD")
fmt.Println(currencyUS.Name) //US Dollar
fmt.Println(currencyUS.Symbol) //$
relativeDate = time.Now().Add(-365 * date_time.Day).Format(time.RFC3339)
relativeTime, err = date_time.GetRelativeTime(relativeDate, date_time.DateTimeOptions{
BaseDate: currentDate,
})
fmt.Println("Relative time (past) - ", relativeTime, err) // 1 Year ago

// add convert to major unit and minor unit examples
}
97 changes: 97 additions & 0 deletions packages/i18nify-go/modules/date_time/date_time.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
// Package date_time provides utilities for date and time formatting, parsing, and manipulation.
package date_time

import (
"errors"
"fmt"
"time"
)

// exported constants for time duration
const (
Minute = time.Minute
Hour = time.Hour
Day = Hour * 24
Week = Day * 7
Month = Day * 30
Year = Month * 12
)

// IntlOptions represents the options for formatting the date and time.
type IntlOptions struct {
// Locale - Locale by which the timezone should be formatted/converted.
// Valid examples include "IST", "UTC", "GMT", "GMT+2"
// Invalid Locale will by default get converted to UTC
Locale string
// Hour12 - boolean flag to identify the time format
Hour12 *bool
}

// DateTimeModeOption represents the different modes of date-time formatting
type DateTimeModeOption string

const (
DateTimeMode DateTimeModeOption = "dateTime"
DateOnlyMode DateTimeModeOption = "dateOnly"
TimeOnlyMode DateTimeModeOption = "timeOnly"
)

// DateTimeOptions represents the configuration for date-time formatting
type DateTimeOptions struct {
// DateTimeMode - DateTime format, examples: "dateTime", "dateOnly", "timeOnly"
// by default or illegal value passed takes dateOnly mode
// Exported through DateTimeModeOption
DateTimeMode DateTimeModeOption
// BaseDate - Base date in case of getting relative time
BaseDate string
// IntlOptions - Options for providing flags/details related to internationalization of date
IntlOptions *IntlOptions
}

// stringToDate converts a date string into a Go time.Time object.
func stringToDate(dateString string) (time.Time, error) {
for _, format := range SupportedDateFormats {
if format.Regex != nil {
// Handle custom regex formats
if matches := format.Regex.FindStringSubmatch(dateString); matches != nil {
year := matches[format.YearIndex]
month := matches[format.MonthIndex]
day := matches[format.DayIndex]
hour, minute, second := "00", "00", "00"

if format.HourIndex > 0 {
hour = matches[format.HourIndex]
minute = matches[format.MinuteIndex]
second = matches[format.SecondIndex]
}

combined := fmt.Sprintf("%s-%s-%sT%s:%s:%sZ", year, month, day, hour, minute, second)
return time.Parse(time.RFC3339, combined)
}
} else if format.Format != "" {
// Handle Go's standard layouts
if parsedTime, err := time.Parse(format.Format, dateString); err == nil {
return parsedTime, nil
}
}
}

return time.Time{}, fmt.Errorf("date format not recognized: %s", dateString)
}

// convertToStandardDate converts a date input (string or time.Time) into a standardized time.Time object.
func convertToStandardDate(dateInput interface{}) (time.Time, error) {
switch date := dateInput.(type) {
case string:
return stringToDate(date)
case time.Time:
return date, nil
default:
return time.Time{}, errors.New("unsupported date input type")
}
}

// StringToDate converts a string representation of a date into a time.Time object.
func StringToDate(dateStr string) (time.Time, error) {
return convertToStandardDate(dateStr)
}
70 changes: 70 additions & 0 deletions packages/i18nify-go/modules/date_time/date_time_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package date_time

import (
"testing"
"time"
)

// Additional test for date parsing functionality
func TestParseDateTime(t *testing.T) {
tests := []struct {
name string
input string
expectError bool
}{
{
name: "parses RFC3339",
input: time.Now().Format(time.RFC3339),
},
{
name: "parses ISO format",
input: "2024-01-02T15:04:05",
},
{
name: "parses date only",
input: "2024-01-02",
},
{
name: "fails on invalid format",
input: "invalid-date",
expectError: true,
},
{
name: "fails on empty string",
input: "",
expectError: true,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
_, err := convertToStandardDate(tt.input)
if tt.expectError && err == nil {
t.Error("expected error but got none")
}
if !tt.expectError && err != nil {
t.Errorf("unexpected error: %v", err)
}
})
}
}

func TestStringToDate(t *testing.T) {
dateStr := "2024-12-16 10:30:00"
layout := "2006-01-02 15:04:05"

// Positive case
parsedDate, err := StringToDate(dateStr)
if err != nil {
t.Errorf("unexpected error: %v", err)
}
if parsedDate.Format(layout) != dateStr {
t.Errorf("expected '%s', got '%s'", dateStr, parsedDate.Format(layout))
}

// Negative case
_, err = StringToDate("not-a-date")
if err == nil {
t.Error("expected an error for invalid date string")
}
}
Loading
Loading