Skip to content
Open
Show file tree
Hide file tree
Changes from 7 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"

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

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