Skip to content
Merged
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
8 changes: 8 additions & 0 deletions internal/exercises/catalog.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -177,3 +177,11 @@ projects:
hints:
- Implement an in-memory key-value store with basic CRUD operations and optional persistence.

- slug: 36_epoch
title: "Epoch Conversion"
difficulty: beginner
topics: ["time", "epoch", "unix"]
hints:
- "Use Go's `time.Unix()` to convert an epoch to time."
- "Use `t.Unix()` to convert time back to epoch."
- "Remember Go’s `time.Parse` can help parse date strings."
74 changes: 74 additions & 0 deletions internal/exercises/solutions/36_epoch/epoch.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package epoch

import (
"time"
)
Comment on lines +3 to +5

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

Add fmt import for numeric string conversions.

To implement the fixes suggested for NowFormats(), you'll need to add the fmt package import.

 import (
+	"fmt"
 	"time"
 )
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import (
"time"
)
import (
"fmt"
"time"
)
🤖 Prompt for AI Agents
In internal/exercises/solutions/36_epoch/epoch.go around lines 3 to 5, the code
needs the fmt package imported to support numeric-to-string conversions used in
NowFormats(); add fmt to the import block (e.g., include "fmt" alongside "time")
so the formatting functions compile and can convert numbers to strings as
required.


// --- Getting Current Time ---

// GetCurrentUnixSeconds returns the current time as a Unix epoch in seconds (int64).
func GetCurrentUnixSeconds() int64 {
return time.Now().Unix()
}

// GetCurrentUnixMilliseconds returns the current time as a Unix epoch in milliseconds (int64).
func GetCurrentUnixMilliseconds() int64 {
return time.Now().UnixNano() / int64(time.Millisecond)
}

// GetCurrentUnixNanoseconds returns the current time as a Unix epoch in nanoseconds (int64).
func GetCurrentUnixNanoseconds() int64 {
return time.Now().UnixNano()
}

// GetCurrentFormattedTime returns the current time in the
// "2006-01-02 15:04:05.000000 +0000 UTC" format (microsecond precision).
func GetCurrentFormattedTime() string {
return time.Now().UTC().Format("2006-01-02 15:04:05.000000 +0000 UTC")
}

// GetCurrentFormattedTimeSimple returns the current time in the
// "2006-01-02 15:04:05 +0000 UTC" format (no microseconds).
func GetCurrentFormattedTimeSimple() string {
return time.Now().UTC().Format("2006-01-02 15:04:05 +0000 UTC")
}



// EpochToTime converts a unix epoch (seconds) into a formatted time string "2006-01-02 15:04:05".
// The resulting time is in UTC.
func EpochToTime(epoch int64) string {
t := time.Unix(epoch, 0).UTC()
return t.Format("2006-01-02 15:04:05")
}

// TimeToEpoch converts a formatted time string "2006-01-02 15:04:05" into a unix epoch (seconds).
// It assumes the input string represents a time in UTC.
func TimeToEpoch(input string) int64 {
t, err := time.ParseInLocation("2006-01-02 15:04:05", input, time.UTC)
if err != nil {
return 0
}
return t.Unix()
}
Comment on lines +47 to +53

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Error handling creates ambiguity.

Returning 0 on parse errors is problematic because 0 is a valid Unix epoch (January 1, 1970). Callers cannot distinguish between a parsing error and the actual epoch zero.

Consider one of these approaches:

Option 1: Return error as second value (idiomatic Go):

-func TimeToEpoch(input string) int64 {
+func TimeToEpoch(input string) (int64, error) {
 	t, err := time.ParseInLocation("2006-01-02 15:04:05", input, time.UTC)
 	if err != nil {
-		return 0
+		return 0, err
 	}
-	return t.Unix()
+	return t.Unix(), nil
 }

Option 2: Use sentinel value (if constrained by test signature):

 func TimeToEpoch(input string) int64 {
 	t, err := time.ParseInLocation("2006-01-02 15:04:05", input, time.UTC)
 	if err != nil {
-		return 0
+		return -1  // or panic/log the error
 	}
 	return t.Unix()
 }

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
internal/exercises/solutions/36_epoch/epoch.go lines 47-53: The function
currently returns 0 on parse errors which is ambiguous because 0 is a valid Unix
epoch; change the signature to return (int64, error), parse the time and on
success return t.Unix(), nil, and on failure return 0 and the parse error, then
update any callers/tests to handle the error; if changing signature is not
possible, return a documented sentinel (e.g. -1) on error and ensure callers
check for that sentinel.



// NowFormats returns the current time in all supported formats.
func NowFormats() map[string]string {
now := time.Now().UTC()
return map[string]string{
"UnixSeconds": time.Unix(now.Unix(), 0).Format("2006-01-02 15:04:05") + " (epoch: " +
time.Unix(now.Unix(), 0).UTC().Format("2006-01-02 15:04:05") + ")",
"UnixSecondsRaw": time.Unix(now.Unix(), 0).UTC().Format("2006-01-02 15:04:05"),
"UnixSecondsInt": formatInt(now.Unix()),
"UnixMilliseconds": formatInt(now.UnixMilli()),
"UnixNanoseconds": formatInt(now.UnixNano()),
"FormattedFull": GetCurrentFormattedTime(),
"FormattedSimple": GetCurrentFormattedTimeSimple(),
}
}
Comment on lines +57 to +69

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Critical logic error in NowFormats.

The UnixSecondsInt, UnixMilliseconds, and UnixNanoseconds entries incorrectly use formatInt() which converts the numeric epoch values back into date strings. These should return the raw numeric values as strings.

Apply this diff:

 func NowFormats() map[string]string {
 	now := time.Now().UTC()
 	return map[string]string{
-		"UnixSeconds":      time.Unix(now.Unix(), 0).Format("2006-01-02 15:04:05") + " (epoch: " + 
-		                    time.Unix(now.Unix(), 0).UTC().Format("2006-01-02 15:04:05") + ")",
-		"UnixSecondsRaw":   time.Unix(now.Unix(), 0).UTC().Format("2006-01-02 15:04:05"),
-		"UnixSecondsInt":   formatInt(now.Unix()),
-		"UnixMilliseconds": formatInt(now.UnixMilli()),
-		"UnixNanoseconds":  formatInt(now.UnixNano()),
+		"UnixSeconds":      now.Format("2006-01-02 15:04:05 +0000 UTC"),
+		"UnixSecondsRaw":   now.Format("2006-01-02 15:04:05"),
+		"UnixSecondsInt":   fmt.Sprintf("%d", now.Unix()),
+		"UnixMilliseconds": fmt.Sprintf("%d", now.UnixMilli()),
+		"UnixNanoseconds":  fmt.Sprintf("%d", now.UnixNano()),
 		"FormattedFull":    GetCurrentFormattedTime(),
 		"FormattedSimple":  GetCurrentFormattedTimeSimple(),
 	}
 }

You'll also need to import fmt at the top of the file.

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In internal/exercises/solutions/36_epoch/epoch.go around lines 57 to 69, the
entries for UnixSecondsInt, UnixMilliseconds, and UnixNanoseconds incorrectly
call formatInt (which converts epoch values to date strings); replace those
calls with fmt.Sprintf("%d", <numeric>) to return the raw numeric epoch values
as strings (use now.Unix(), now.UnixMilli(), and now.UnixNano() respectively),
and add an import for "fmt" at the top of the file.


// Helper: format int64 as string
func formatInt(val int64) string {
return time.Unix(0, val).UTC().Format("2006-01-02 15:04:05")
}
15 changes: 15 additions & 0 deletions internal/exercises/templates/36_epoch/epoch.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package epoch

// TODO: Implement these functions so tests pass

// EpochToTime converts a unix epoch (seconds) into a formatted time string "2006-01-02 15:04:05".
func EpochToTime(epoch int64) string {
// Intentionally wrong to simulate failing exercise
return ""
}

// TimeToEpoch converts a formatted time string "2006-01-02 15:04:05" into a unix epoch (seconds).
func TimeToEpoch(input string) int64 {
// Intentionally wrong to simulate failing exercise
return 0
}
20 changes: 20 additions & 0 deletions internal/exercises/templates/36_epoch/epoch_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package epoch

import "testing"

func TestEpochToTime(t *testing.T) {
const want = "2021-10-01 00:00:00"
const epoch = int64(1633046400) // 2021-10-01 00:00:00 UTC
got := EpochToTime(epoch)
if got != want {
t.Fatalf("EpochToTime(%d) = %q, want %q", epoch, got, want)
}
}
func TestTimeToEpoch(t *testing.T) {
const input = "2021-10-01 00:00:00"
const want = int64(1633046400)
got := TimeToEpoch(input)
if got != want {
t.Fatalf("TimeToEpoch(%q) = %d, want %d", input, got, want)
}
}
Loading