Skip to content

Commit 09ad066

Browse files
authored
Merge pull request #140 from Flipez/add-time-parse-format
[stdlib/time] Add support for `Time.format()` and `Time.parse()`
2 parents c7f4a10 + 0845a67 commit 09ad066

3 files changed

Lines changed: 216 additions & 0 deletions

File tree

docs/docs/builtins/Time.md

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,42 @@
55

66
## Module Function
77

8+
### format(INTEGER, STRING)
9+
> Returns `STRING`
10+
11+
Formats the given unix timestamp with the given layout.
12+
13+
[Go date and time formats](https://gosamples.dev/date-time-format-cheatsheet/) are natively supported.
14+
You can also use some but not all [formats present in many other languages](https://apidock.com/ruby/Time/strftime) which are not fully supported.
15+
Take a look at [the source](https://github.com/Flipez/rocket-lang/blob/main/stdlib/time.go) to see which formatters are supported.
16+
17+
18+
```js
19+
🚀 » Time.format(Time.unix(), "Mon Jan _2 15:04:05 2006")
20+
» "Mon Oct 31 00:08:10 2022"
21+
🚀 » Time.format(Time.unix(), "%a %b %e %H:%M:%S %Y")
22+
» "Mon Oct 31 00:28:43 2022"
23+
```
24+
25+
26+
### parse(STRING, STRING)
27+
> Returns `STRING`
28+
29+
Parses a given string with the given format to a unix timestamp.
30+
31+
[Go date and time formats](https://gosamples.dev/date-time-format-cheatsheet/) are natively supported.
32+
You can also use some but not all [formats present in many other languages](https://apidock.com/ruby/Time/strftime) which are not fully supported.
33+
Take a look at [the source](https://github.com/Flipez/rocket-lang/blob/main/stdlib/time.go) to see which formatters are supported.
34+
35+
36+
```js
37+
🚀 » Time.parse("2022-03-23", "2006-01-02")
38+
» 1647993600
39+
🚀 » Time.parse("2022-03-23", "%Y-%m-%d")
40+
» 1647993600
41+
```
42+
43+
844
### sleep(INTEGER)
945
> Returns `NIL`
1046
@@ -31,3 +67,19 @@ Returns the current time as unix timestamp
3167
## Properties
3268
| Name | Value |
3369
| ---- | ----- |
70+
| ANSIC | Mon Jan _2 15:04:05 2006 |
71+
| Kitchen | 3:04PM |
72+
| Layout | 01/02 03:04:05PM '06 -0700 |
73+
| RFC1123 | Mon, 02 Jan 2006 15:04:05 MST |
74+
| RFC1123Z | Mon, 02 Jan 2006 15:04:05 -0700 |
75+
| RFC3339 | 2006-01-02T15:04:05Z07:00 |
76+
| RFC3339Nano | 2006-01-02T15:04:05.999999999Z07:00 |
77+
| RFC822 | 02 Jan 06 15:04 MST |
78+
| RFC822Z | 02 Jan 06 15:04 -0700 |
79+
| RFC850 | Monday, 02-Jan-06 15:04:05 MST |
80+
| RubyDate | Mon Jan 02 15:04:05 -0700 2006 |
81+
| Stamp | Jan _2 15:04:05 |
82+
| StampMicro | Jan _2 15:04:05.000000 |
83+
| StampMilli | Jan _2 15:04:05.000 |
84+
| StampNano | Jan _2 15:04:05.000000000 |
85+
| UnixDate | Mon Jan _2 15:04:05 MST 2006 |

object/time_test.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package object_test
2+
3+
import (
4+
"testing"
5+
"time"
6+
)
7+
8+
func TestTimeModule(t *testing.T) {
9+
tests := []inputTestCase{
10+
{`Time.Layout`, time.Layout},
11+
{`Time.ANSIC`, time.ANSIC},
12+
{`Time.UnixDate`, time.UnixDate},
13+
{`Time.RubyDate`, time.RubyDate},
14+
{`Time.RFC822`, time.RFC822},
15+
{`Time.RFC822Z`, time.RFC822Z},
16+
{`Time.RFC850`, time.RFC850},
17+
{`Time.RFC1123`, time.RFC1123},
18+
{`Time.RFC1123Z`, time.RFC1123Z},
19+
{`Time.RFC3339`, time.RFC3339},
20+
{`Time.RFC3339Nano`, time.RFC3339Nano},
21+
{`Time.Kitchen`, time.Kitchen},
22+
{`Time.Stamp`, time.Stamp},
23+
{`Time.StampMilli`, time.StampMilli},
24+
{`Time.StampMicro`, time.StampMicro},
25+
{`Time.StampNano`, time.StampNano},
26+
}
27+
28+
testInput(t, tests)
29+
}
30+
31+
func TestTimeObjectMethods(t *testing.T) {
32+
tests := []inputTestCase{
33+
{`a = 1667144827; Time.format(a, "%a %b %e %M:%S %Y")`, "Sun Oct 30 47:07 2022"},
34+
{`a = 1667144827; Time.format(a, "Mon Jan _2 04:05 2006")`, "Sun Oct 30 47:07 2022"},
35+
{`a = "2022-03-23"; format = "2006-01-02"; Time.parse(a, format)`, 1647993600},
36+
{`a = "2022-03-23"; format = "09-01-02"; Time.parse(a, format)`, `Error while parsing time: parsing time "2022-03-23" as "09-01-02": cannot parse "2022-03-23" as "09-"`},
37+
}
38+
39+
testInput(t, tests)
40+
}

stdlib/time.go

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package stdlib
22

33
import (
4+
"strings"
45
"time"
56

67
"github.com/flipez/rocket-lang/object"
@@ -9,7 +10,105 @@ import (
910
var timeFunctions = map[string]*object.BuiltinFunction{}
1011
var timeProperties = map[string]*object.BuiltinProperty{}
1112

13+
var timeFormatConversions = map[string]string{
14+
// year format
15+
"%Y": "2006", // Four-digit year
16+
"%y": "06", // Two digit year
17+
18+
// month format
19+
"%B": "January", // Full month name
20+
"%b": "Jan", // Three-letter abbr. of the month
21+
"%m": "01", // Two digit month (leading 0)
22+
"%-m": "1", // At most two-digit month (without leading 0)
23+
24+
// day format
25+
"%A": "Monday", // Full weekday
26+
"%a": "Mon", // Three letter weekday
27+
"%d": "02", // Two-digit month day
28+
"%e": "_2", // Two-character month day with leading space
29+
"%-d": "2", // At most two-digit month day
30+
"%j": "002", // Three digit day of the year
31+
32+
// hour format
33+
"%H": "15", // Two-digit 24h format hour
34+
"%I": "03", // Two digit 12h format hour (with a leading 0 if necessary)
35+
"%l": "3", // At most two-digit 12h format hour (without a leading 0)
36+
"%p": "PM", // AM/PM mark (uppercase)
37+
"%P": "pm", // AM/PM mark (lowercase)
38+
39+
// minute format
40+
"%M": "04", // Two-digit minute (with a leading 0 if necessary)
41+
42+
// second format
43+
"%S": "05", // Two-digit second (with a leading 0 if necessary)
44+
45+
// time zone format
46+
"%Z": "MST", // Abbreviation of the time zone
47+
"%::z": "-07:00:00", // Numeric time zone offset with hours, minutes, and seconds separated by colon
48+
"%z": "-0700", // Numeric time zone offset with hours and minutes
49+
"%:z": "-07:00", // Numeric time zone offset with hours and minutes separated by colons
50+
}
51+
1252
func init() {
53+
timeFunctions["format"] = object.NewBuiltinFunction(
54+
"format",
55+
object.MethodLayout{
56+
Description: `Formats the given unix timestamp with the given layout.
57+
58+
[Go date and time formats](https://gosamples.dev/date-time-format-cheatsheet/) are natively supported.
59+
You can also use some but not all [formats present in many other languages](https://apidock.com/ruby/Time/strftime) which are not fully supported.
60+
Take a look at [the source](https://github.com/Flipez/rocket-lang/blob/main/stdlib/time.go) to see which formatters are supported.`,
61+
ArgPattern: object.Args(
62+
object.Arg(object.INTEGER_OBJ),
63+
object.Arg(object.STRING_OBJ),
64+
),
65+
ReturnPattern: object.Args(
66+
object.Arg(object.STRING_OBJ),
67+
),
68+
Example: `🚀 » Time.format(Time.unix(), "Mon Jan _2 15:04:05 2006")
69+
» "Mon Oct 31 00:08:10 2022"
70+
🚀 » Time.format(Time.unix(), "%a %b %e %H:%M:%S %Y")
71+
» "Mon Oct 31 00:28:43 2022"`,
72+
},
73+
func(_ object.Environment, args ...object.Object) object.Object {
74+
unixTimestamp := args[0].(*object.Integer)
75+
timeFormat := args[1].(*object.String)
76+
77+
time := time.Unix(unixTimestamp.Value, 0)
78+
79+
return object.NewString(time.Format(convertTimeFormat(timeFormat)))
80+
})
81+
timeFunctions["parse"] = object.NewBuiltinFunction(
82+
"parse",
83+
object.MethodLayout{
84+
Description: `Parses a given string with the given format to a unix timestamp.
85+
86+
[Go date and time formats](https://gosamples.dev/date-time-format-cheatsheet/) are natively supported.
87+
You can also use some but not all [formats present in many other languages](https://apidock.com/ruby/Time/strftime) which are not fully supported.
88+
Take a look at [the source](https://github.com/Flipez/rocket-lang/blob/main/stdlib/time.go) to see which formatters are supported.`,
89+
ArgPattern: object.Args(
90+
object.Arg(object.STRING_OBJ),
91+
object.Arg(object.STRING_OBJ),
92+
),
93+
ReturnPattern: object.Args(
94+
object.Arg(object.STRING_OBJ),
95+
),
96+
Example: `🚀 » Time.parse("2022-03-23", "2006-01-02")
97+
» 1647993600
98+
🚀 » Time.parse("2022-03-23", "%Y-%m-%d")
99+
» 1647993600`,
100+
},
101+
func(_ object.Environment, args ...object.Object) object.Object {
102+
timeString := args[0].(*object.String)
103+
timeFormat := args[1].(*object.String)
104+
105+
timeParsed, err := time.Parse(convertTimeFormat(timeFormat), timeString.Value)
106+
if err != nil {
107+
return object.NewErrorFormat("Error while parsing time: %s", err)
108+
}
109+
110+
return object.NewInteger(timeParsed.Unix())
111+
})
13112
timeFunctions["sleep"] = object.NewBuiltinFunction(
14113
"sleep",
15114
object.MethodLayout{
@@ -38,4 +137,29 @@ func init() {
38137
func(_ object.Environment, args ...object.Object) object.Object {
39138
return object.NewInteger(time.Now().Unix())
40139
})
140+
141+
timeProperties["Layout"] = object.NewBuiltinProperty("Layout", object.NewString(time.Layout))
142+
timeProperties["ANSIC"] = object.NewBuiltinProperty("ANSIC", object.NewString(time.ANSIC))
143+
timeProperties["UnixDate"] = object.NewBuiltinProperty("UnixDate", object.NewString(time.UnixDate))
144+
timeProperties["RubyDate"] = object.NewBuiltinProperty("RubyDate", object.NewString(time.RubyDate))
145+
timeProperties["RFC822"] = object.NewBuiltinProperty("RFC822", object.NewString(time.RFC822))
146+
timeProperties["RFC822Z"] = object.NewBuiltinProperty("RFC822Z", object.NewString(time.RFC822Z))
147+
timeProperties["RFC850"] = object.NewBuiltinProperty("RFC850", object.NewString(time.RFC850))
148+
timeProperties["RFC1123"] = object.NewBuiltinProperty("RFC1123", object.NewString(time.RFC1123))
149+
timeProperties["RFC1123Z"] = object.NewBuiltinProperty("RFC1123Z", object.NewString(time.RFC1123Z))
150+
timeProperties["RFC3339"] = object.NewBuiltinProperty("RFC3339", object.NewString(time.RFC3339))
151+
timeProperties["RFC3339Nano"] = object.NewBuiltinProperty("RFC3339Nano", object.NewString(time.RFC3339Nano))
152+
timeProperties["Kitchen"] = object.NewBuiltinProperty("Kitchen", object.NewString(time.Kitchen))
153+
timeProperties["Stamp"] = object.NewBuiltinProperty("Stamp", object.NewString(time.Stamp))
154+
timeProperties["StampMilli"] = object.NewBuiltinProperty("StampMilli", object.NewString(time.StampMilli))
155+
timeProperties["StampMicro"] = object.NewBuiltinProperty("StampMicro", object.NewString(time.StampMicro))
156+
timeProperties["StampNano"] = object.NewBuiltinProperty("StampNano", object.NewString(time.StampNano))
157+
}
158+
159+
func convertTimeFormat(format *object.String) string {
160+
timeFormat := format.Value
161+
for strfmtFormat, golangFormat := range timeFormatConversions {
162+
timeFormat = strings.ReplaceAll(timeFormat, strfmtFormat, golangFormat)
163+
}
164+
return timeFormat
41165
}

0 commit comments

Comments
 (0)