Skip to content
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
1 change: 1 addition & 0 deletions docs/exercises.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ title: Exercises
<li>107_image_processing_utility - Image processing (Hard)</li>
<li>108_basic_key_value_store - Key-value store (Hard)</li>
<li>109_epoch - Time conversion (Beginner)</li>
<li>120_time - Time functions exercise (Beginner)</li>
</ul>
</div>

Expand Down
8 changes: 8 additions & 0 deletions internal/exercises/catalog.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,14 @@ projects:
- "Use sort.Sort() to sort slices with your custom comparison logic"
- "Remember to make copies of slices to avoid modifying the original"

- slug: 120_time
title: "Time"
description: "Practice working with Go’s time package: formatting dates and computing day differences."
template: "templates/time.go"
test: "templates/time_test.go"
hints:
- "Use time.Format with layout \"2006-01-02\""
- "Subtract two times to get a Duration, then convert to hours and divide by 24"
- slug: 38_time_formatting
title: "Time Formatting"
difficulty: beginner
Expand Down
50 changes: 50 additions & 0 deletions internal/exercises/solutions/120_time/time.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package time

import "time"

// FormatDate formats a time.Time into "YYYY-MM-DD".
func FormatDate(t time.Time) string {
return t.Format("2006-01-02")
}

// FormatDateTime formats a time.Time into "YYYY-MM-DD HH:MM:SS".
func FormatDateTime(t time.Time) string {
return t.Format("2006-01-02 15:04:05")
}

// DaysBetween returns the number of days between two dates.
// Positive if end > start, negative if end < start.
//
// Note: This implementation divides the duration by 24 hours.
// When dates span a daylight saving time (DST) transition, the result
// may be off by ±1 hour. For exact day counts across DST, consider
// normalizing both dates to UTC or comparing date components at midnight.
func DaysBetween(start, end time.Time) int {
return int(end.Sub(start).Hours() / 24)
}


// AddDays adds a specified number of days to a date and returns the new date.
func AddDays(t time.Time, days int) time.Time {
return t.AddDate(0, 0, days)
}

// ParseDate parses a string in "YYYY-MM-DD" format into a time.Time.
// Returns zero time if parsing fails.
func ParseDate(s string) time.Time {
t, err := time.Parse("2006-01-02", s)
if err != nil {
return time.Time{}
}
return t
}

// ParseDateTime parses a string in "YYYY-MM-DD HH:MM:SS" format into a time.Time.
// Returns zero time if parsing fails.
func ParseDateTime(s string) time.Time {
t, err := time.Parse("2006-01-02 15:04:05", s)
if err != nil {
return time.Time{}
}
return t
}
44 changes: 44 additions & 0 deletions internal/exercises/templates/120_time/time.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package timeutils

import "time"

// FormatDate formats a time.Time into "YYYY-MM-DD".
func FormatDate(t time.Time) string {
return t.Format("2006-01-02")
}

// FormatDateTime formats a time.Time into "YYYY-MM-DD HH:MM:SS".
func FormatDateTime(t time.Time) string {
return t.Format("2006-01-02 15:04:05")
}

// DaysBetween returns the number of days between two dates.
// Positive if end > start, negative if end < start.
func DaysBetween(start, end time.Time) int {
return int(end.Sub(start).Hours() / 24)
}

// AddDays adds a specified number of days to a date and returns the new date.
func AddDays(t time.Time, days int) time.Time {
return t.AddDate(0, 0, days)
}

// ParseDate parses a string in "YYYY-MM-DD" format into a time.Time.
// Returns zero time if parsing fails.
func ParseDate(s string) time.Time {
t, err := time.Parse("2006-01-02", s)
if err != nil {
return time.Time{}
}
return t
}

// ParseDateTime parses a string in "YYYY-MM-DD HH:MM:SS" format into a time.Time.
// Returns zero time if parsing fails.
func ParseDateTime(s string) time.Time {
t, err := time.Parse("2006-01-02 15:04:05", s)
if err != nil {
return time.Time{}
}
return t
}
82 changes: 82 additions & 0 deletions internal/exercises/templates/120_time/time_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package timeutils_test

import (
"testing"
"time"

timeutils "github.com/zhravan/golearn/internal/exercises/templates/120_time"
)

// Helper to quickly create a date
func mustDate(year int, month time.Month, day int) time.Time {
return time.Date(year, month, day, 0, 0, 0, 0, time.UTC)
}

// --- Tests for FormatDate ---
func TestFormatDate(t *testing.T) {
d := mustDate(2025, time.October, 2)
want := "2025-10-02"
got := timeutils.FormatDate(d)
if got != want {
t.Fatalf("FormatDate(%v) = %q; want %q", d, got, want)
}
}

// --- Tests for FormatDateTime ---
func TestFormatDateTime(t *testing.T) {
d := mustDate(2025, time.October, 2)
want := "2025-10-02 00:00:00"
got := timeutils.FormatDateTime(d)
if got != want {
t.Fatalf("FormatDateTime(%v) = %q; want %q", d, got, want)
}
}

// --- Tests for DaysBetween ---
func TestDaysBetween(t *testing.T) {
start := mustDate(2025, time.October, 1)
end := mustDate(2025, time.October, 11)

got := timeutils.DaysBetween(start, end)
want := 10
if got != want {
t.Fatalf("DaysBetween(%v, %v) = %d; want %d", start, end, got, want)
}

// negative difference
got = timeutils.DaysBetween(end, start)
want = -10
if got != want {
t.Fatalf("DaysBetween(%v, %v) = %d; want %d", end, start, got, want)
}
}

// --- Tests for AddDays ---
func TestAddDays(t *testing.T) {
d := mustDate(2025, time.October, 1)
got := timeutils.AddDays(d, 10)
want := mustDate(2025, time.October, 11)
if !got.Equal(want) {
t.Fatalf("AddDays(%v, 10) = %v; want %v", d, got, want)
}
}

// --- Tests for ParseDate ---
func TestParseDate(t *testing.T) {
input := "2025-10-02"
want := mustDate(2025, time.October, 2)
got := timeutils.ParseDate(input)
if !got.Equal(want) {
t.Fatalf("ParseDate(%q) = %v; want %v", input, got, want)
}
}

// --- Tests for ParseDateTime ---
func TestParseDateTime(t *testing.T) {
input := "2025-10-02 00:00:00"
want := mustDate(2025, time.October, 2)
got := timeutils.ParseDateTime(input)
if !got.Equal(want) {
t.Fatalf("ParseDateTime(%q) = %v; want %v", input, got, want)
}
}