-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #11 from Code-Hex/add/change-advance
added Advance and Change
- Loading branch information
Showing
4 changed files
with
346 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,221 @@ | ||
package synchro | ||
|
||
import ( | ||
"time" | ||
|
||
"github.com/Code-Hex/synchro/tz" | ||
) | ||
|
||
func toPtr[T any](x T) *T { | ||
return &x | ||
} | ||
|
||
// TimeBuilder defines an interface for constructing a Time[T] value | ||
// with specific date and time components using method chaining. | ||
// | ||
// Implementations should allow for setting each component step by step, | ||
// and then finalizing the construction with the Do() method. | ||
type TimeBuilder[T TimeZone] interface { | ||
// Year sets the year component of the time being built. | ||
Year(int) TimeBuilder[T] | ||
|
||
// Month sets the month component of the time being built. | ||
Month(time.Month) TimeBuilder[T] | ||
|
||
// Day sets the day component of the time being built. | ||
Day(int) TimeBuilder[T] | ||
|
||
// Hour sets the hour component of the time being built. | ||
Hour(int) TimeBuilder[T] | ||
|
||
// Minute sets the minute component of the time being built. | ||
Minute(int) TimeBuilder[T] | ||
|
||
// Second sets the second component of the time being built. | ||
Second(int) TimeBuilder[T] | ||
|
||
// Nanosecond sets the nanosecond component of the time being built. | ||
Nanosecond(int) TimeBuilder[T] | ||
|
||
// Do finalizes and returns the constructed Time value | ||
// based on the components set in the chain. | ||
Do() Time[T] | ||
} | ||
|
||
type changeBuilder[T TimeZone] struct { | ||
year *int | ||
month *time.Month | ||
day *int | ||
hour *int | ||
minute *int | ||
second *int | ||
nsec *int | ||
|
||
t Time[T] | ||
} | ||
|
||
var _ TimeBuilder[tz.UTC] = changeBuilder[tz.UTC]{} | ||
|
||
// Year implements the TimeBuilder interface to change years. | ||
func (c changeBuilder[T]) Year(year int) TimeBuilder[T] { | ||
c.year = toPtr(year) | ||
return c | ||
} | ||
|
||
// Month implements the TimeBuilder interface to change months. | ||
func (c changeBuilder[T]) Month(month time.Month) TimeBuilder[T] { | ||
c.month = toPtr(month) | ||
return c | ||
} | ||
|
||
// Day implements the TimeBuilder interface to change days. | ||
func (c changeBuilder[T]) Day(day int) TimeBuilder[T] { | ||
c.day = toPtr(day) | ||
return c | ||
} | ||
|
||
// Hour implements the TimeBuilder interface to change hours. | ||
func (c changeBuilder[T]) Hour(hour int) TimeBuilder[T] { | ||
c.hour = toPtr(hour) | ||
return c | ||
} | ||
|
||
// Minute implements the TimeBuilder interface to change minutes. | ||
func (c changeBuilder[T]) Minute(minute int) TimeBuilder[T] { | ||
c.minute = toPtr(minute) | ||
return c | ||
} | ||
|
||
// Second implements the TimeBuilder interface to change seconds. | ||
func (c changeBuilder[T]) Second(second int) TimeBuilder[T] { | ||
c.second = toPtr(second) | ||
return c | ||
} | ||
|
||
// Nanosecond implements the TimeBuilder interface to change nanoseconds. | ||
func (c changeBuilder[T]) Nanosecond(nsec int) TimeBuilder[T] { | ||
c.nsec = toPtr(nsec) | ||
return c | ||
} | ||
|
||
// Do implements the TimeBuilder interface to change any date and time components. | ||
func (c changeBuilder[T]) Do() Time[T] { | ||
year, month, day := c.t.Date() | ||
hour, min, sec := c.t.Clock() | ||
nsec := c.t.Nanosecond() | ||
if c.year != nil { | ||
year = *c.year | ||
} | ||
if c.month != nil { | ||
month = *c.month | ||
} | ||
if c.day != nil { | ||
day = *c.day | ||
} | ||
if c.hour != nil { | ||
hour = *c.hour | ||
} | ||
if c.minute != nil { | ||
min = *c.minute | ||
} | ||
if c.second != nil { | ||
sec = *c.second | ||
} | ||
if c.nsec != nil { | ||
nsec = *c.nsec | ||
} | ||
return New[T](year, month, day, hour, min, sec, nsec) | ||
} | ||
|
||
// Change initializes and returns a TimeBuilder for the current Time value. | ||
// | ||
// This provides a method chain approach for specifying which parts of the time | ||
// you want to change, allowing for the creation of a new Time[T] instance | ||
// with the specified modifications. | ||
func (t Time[T]) Change() TimeBuilder[T] { | ||
return changeBuilder[T]{t: t} | ||
} | ||
|
||
type advanceBuilder[T TimeZone] struct { | ||
year int | ||
month time.Month | ||
day int | ||
hour int | ||
minute int | ||
second int | ||
nsec int | ||
|
||
t Time[T] | ||
} | ||
|
||
var _ TimeBuilder[tz.UTC] = advanceBuilder[tz.UTC]{} | ||
|
||
// Advance initializes and returns a TimeBuilder for the current Time value. | ||
// | ||
// This provides a method chain approach for specifying which parts of the time | ||
// you want to increment, allowing for the creation of a new Time[T] instance | ||
// with the specified modifications. | ||
func (t Time[T]) Advance() TimeBuilder[T] { | ||
return advanceBuilder[T]{t: t} | ||
} | ||
|
||
// Year implements the TimeBuilder interface to increment years. | ||
func (a advanceBuilder[T]) Year(year int) TimeBuilder[T] { | ||
a.year += year | ||
return a | ||
} | ||
|
||
// Month implements the TimeBuilder interface to increment months. | ||
func (a advanceBuilder[T]) Month(month time.Month) TimeBuilder[T] { | ||
a.month += month | ||
return a | ||
} | ||
|
||
// Day implements the TimeBuilder interface to increment days. | ||
func (a advanceBuilder[T]) Day(day int) TimeBuilder[T] { | ||
a.day += day | ||
return a | ||
} | ||
|
||
// Hour implements the TimeBuilder interface to increment hours. | ||
func (a advanceBuilder[T]) Hour(hour int) TimeBuilder[T] { | ||
a.hour += hour | ||
return a | ||
} | ||
|
||
// Minute implements the TimeBuilder interface to increment minutes. | ||
func (a advanceBuilder[T]) Minute(minute int) TimeBuilder[T] { | ||
a.minute += minute | ||
return a | ||
} | ||
|
||
// Second implements the TimeBuilder interface to increment seconds. | ||
func (a advanceBuilder[T]) Second(second int) TimeBuilder[T] { | ||
a.second += second | ||
return a | ||
} | ||
|
||
// Nanosecond implements the TimeBuilder interface to increment nanoseconds. | ||
func (a advanceBuilder[T]) Nanosecond(nsec int) TimeBuilder[T] { | ||
a.nsec += nsec | ||
return a | ||
} | ||
|
||
// Do implements the TimeBuilder interface to increment any date and time components. | ||
func (a advanceBuilder[T]) Do() Time[T] { | ||
t := a.t.AddDate(a.year, int(a.month), a.day) | ||
|
||
if a.hour != 0 { | ||
t = t.Add(time.Hour * time.Duration(a.hour)) | ||
} | ||
if a.minute != 0 { | ||
t = t.Add(time.Minute * time.Duration(a.minute)) | ||
} | ||
if a.second != 0 { | ||
t = t.Add(time.Second * time.Duration(a.second)) | ||
} | ||
if a.nsec != 0 { | ||
t = t.Add(time.Duration(a.nsec)) | ||
} | ||
return t | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
package synchro_test | ||
|
||
import ( | ||
"fmt" | ||
"testing" | ||
"time" | ||
|
||
"github.com/Code-Hex/synchro" | ||
"github.com/Code-Hex/synchro/tz" | ||
) | ||
|
||
func ExampleTime_Change() { | ||
utc := synchro.New[tz.UTC](2009, time.November, 10, 23, 0, 0, 0) | ||
c1 := utc.Change().Year(2010).Do() | ||
c2 := utc.Change().Year(2010).Month(time.December).Do() | ||
c3 := utc.Change().Year(2010).Month(time.December).Day(1).Do() | ||
c4 := c3.Change().Hour(1).Do() | ||
c5 := c3.Change().Hour(1).Minute(1).Do() | ||
c6 := c3.Change().Hour(1).Minute(1).Second(1).Do() | ||
c7 := c3.Change().Hour(1).Minute(1).Second(1).Nanosecond(123456789).Do() | ||
fmt.Printf("Go launched at %s\n", utc) | ||
fmt.Println(c1) | ||
fmt.Println(c2) | ||
fmt.Println(c3) | ||
fmt.Println(c4) | ||
fmt.Println(c5) | ||
fmt.Println(c6) | ||
fmt.Println(c7) | ||
// Output: | ||
// Go launched at 2009-11-10 23:00:00 +0000 UTC | ||
// 2010-11-10 23:00:00 +0000 UTC | ||
// 2010-12-10 23:00:00 +0000 UTC | ||
// 2010-12-01 23:00:00 +0000 UTC | ||
// 2010-12-01 01:00:00 +0000 UTC | ||
// 2010-12-01 01:01:00 +0000 UTC | ||
// 2010-12-01 01:01:01 +0000 UTC | ||
// 2010-12-01 01:01:01.123456789 +0000 UTC | ||
} | ||
|
||
func ExampleTime_Advance() { | ||
utc := synchro.New[tz.UTC](2009, time.November, 10, 23, 0, 0, 0) | ||
c1 := utc.Advance().Year(1).Do() | ||
c11 := utc.Advance().Year(1).Year(1).Do() // +2 years | ||
|
||
c2 := utc.Advance().Year(1).Month(1).Do() | ||
c3 := utc.Advance().Year(1).Month(1).Day(1).Do() | ||
c4 := c3.Advance().Hour(1).Do() | ||
c5 := c3.Advance().Hour(1).Minute(1).Do() | ||
c6 := c3.Advance().Hour(1).Minute(1).Second(1).Do() | ||
c7 := c3.Advance().Hour(1).Minute(1).Second(1).Nanosecond(123456789).Do() | ||
|
||
fmt.Printf("Go launched at %s\n", utc) | ||
fmt.Println(c1) | ||
fmt.Println(c11) | ||
fmt.Println() | ||
fmt.Println(c2) | ||
fmt.Println(c3) | ||
fmt.Println(c4) | ||
fmt.Println(c5) | ||
fmt.Println(c6) | ||
fmt.Println(c7) | ||
// Output: | ||
// Go launched at 2009-11-10 23:00:00 +0000 UTC | ||
// 2010-11-10 23:00:00 +0000 UTC | ||
// 2011-11-10 23:00:00 +0000 UTC | ||
// | ||
// 2010-12-10 23:00:00 +0000 UTC | ||
// 2010-12-11 23:00:00 +0000 UTC | ||
// 2010-12-12 00:00:00 +0000 UTC | ||
// 2010-12-12 00:01:00 +0000 UTC | ||
// 2010-12-12 00:01:01 +0000 UTC | ||
// 2010-12-12 00:01:01.123456789 +0000 UTC | ||
} | ||
|
||
func TestAdvance(t *testing.T) { | ||
utc := synchro.New[tz.UTC](2009, time.November, 10, 23, 0, 0, 0) | ||
|
||
t.Run("month twice", func(t *testing.T) { | ||
got := utc.Advance().Month(1).Month(2).Do() // +3 months | ||
want := synchro.New[tz.UTC](2010, time.February, 10, 23, 0, 0, 0) | ||
if want != got { | ||
t.Fatalf("- %s\n+ %s", want, got) | ||
} | ||
}) | ||
t.Run("day twice", func(t *testing.T) { | ||
got := utc.Advance().Day(1).Day(2).Do() // +3 days | ||
want := synchro.New[tz.UTC](2009, time.November, 13, 23, 0, 0, 0) | ||
if want != got { | ||
t.Fatalf("- %s\n+ %s", want, got) | ||
} | ||
}) | ||
t.Run("hour twice", func(t *testing.T) { | ||
got := utc.Advance().Hour(1).Hour(2).Do() // +3 hours | ||
want := synchro.New[tz.UTC](2009, time.November, 11, 2, 0, 0, 0) | ||
if want != got { | ||
t.Fatalf("- %s\n+ %s", want, got) | ||
} | ||
}) | ||
t.Run("minute twice", func(t *testing.T) { | ||
got := utc.Advance().Minute(5).Minute(60).Do() // +65 minutes | ||
want := synchro.New[tz.UTC](2009, time.November, 11, 0, 5, 0, 0) | ||
if want != got { | ||
t.Fatalf("- %s\n+ %s", want, got) | ||
} | ||
}) | ||
t.Run("second twice", func(t *testing.T) { | ||
got := utc.Advance().Second(5).Second(60).Do() // +65 seconds | ||
want := synchro.New[tz.UTC](2009, time.November, 10, 23, 1, 5, 0) | ||
if want != got { | ||
t.Fatalf("- %s\n+ %s", want, got) | ||
} | ||
}) | ||
t.Run("nanosec twice", func(t *testing.T) { | ||
got := utc.Advance().Nanosecond(5).Nanosecond(60).Do() // +65 nanosec | ||
want := synchro.New[tz.UTC](2009, time.November, 10, 23, 0, 0, 65) | ||
if want != got { | ||
t.Fatalf("- %s\n+ %s", want, got) | ||
} | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters