diff --git a/README.md b/README.md index d45af30..039435c 100644 --- a/README.md +++ b/README.md @@ -24,17 +24,18 @@ python addon/skyfield/server.py ## Methods -### GET /v1/moonPhaseDate +### GET /api/v1/moonPhaseDate The method returns the Moon parameters for the specified day and time. If the day or time is not specified, the current value for the unspecified fields is taken. If longitude and latitude are specified, the response will contain additional structures. -### Params +#### Params | Parameter | Type | Description | Example Value | | :--- | :--- | :--- | :--- | |`utc` | `string [optional, default="UTC+0"]` | UTC in format `UTC+7`, `UTC+09:30`, `-3` | `UTC+4` |`lang` | `string [optional, default="en"]` | Values available: ("en", "es", "fr", "de", "ru", "jp") | `es` |`precision` | `int [optional, default=2]` | How many digits after ```.``` will be in output. Allowed range: [1, 20] | `5` +|`timeFormat` | `string [optional]` | How the data will be formed. Available values: ISO (default), timestamp, duration or Go format. Duration is seconds between current date and event time.| `duration` |`latitude` | `float [optional, default=none]` | Latitude of viewer's place. Used for moon position calculations: ```MoonDaysDetailed```, ```MoonRiseAndSet```, and ```MoonPosition``` object | `51.1655` |`longitude` | `float [optional, default=none]` | Longitude of viewer's place. Used for moon position calculations: ```MoonDaysDetailed```, ```MoonRiseAndSet```, and ```MoonPosition``` object | `71.4272` |`year` | `int [optional, default=]` | Format: YYYY Allowed range: [1, 9999] | `2025` @@ -44,9 +45,10 @@ The method returns the Moon parameters for the specified day and time. If the da |`minute` | `int [optional, default=]` | Format: m or mm. Allowed range: [0, 59] | `01` or `1` |`second` | `int [optional, default=]` | Format: s or ss. Allowed range: [0, 59] | `01` or `1` + ---------------------------------------------------------------- -### /v1/moonPhaseDate Response: +#### Response: The method returns 6 objects: - ```BeginDay```, ```CurrentState```, ```EndDay``` objects of the ```MoonStat``` structure to display the position of the moon at the beginning of the day, the specified time and the end of the day, respectively; @@ -70,7 +72,7 @@ The method returns 6 objects: ---------------------------------------------------------------- -#### MoonStat (used as ```BeginDay```, ```CurrentState```, ```EndDay```) +##### MoonStat (used as ```BeginDay```, ```CurrentState```, ```EndDay```) ```MoonStat``` objects are used to display at a given time. In case of a method response, MoonStat will contain the values: @@ -110,8 +112,7 @@ MoonPosition structure (Exists only if latitude and longitude are specified): | Response Variable | Type | Description | Example Value | | :--- | :--- | :--- | :--- | -|`MoonPosition.Timestamp` | `Integer [required]` | Unix timestamp of calculation | `1757962800` | -|`MoonPosition.TimeISO` | `String [required]` | ISO 8601 timestamp | `"2025-09-16T00:00:00+05:00"` | +|`MoonPosition.Time` | `String / int64 [required]` | Time in ISO (default) or specified timeFormat | `"2025-09-16T00:00:00+05:00"` | |`MoonPosition.AzimuthDegrees` | `Float [required]` | Compass direction (0°=North) | `57.1` | |`MoonPosition.AltitudeDegrees` | `Float [required]` | Angle above horizon (negative = below) | `8.8` | |`MoonPosition.Direction` | `String [required]` | Cardinal direction abbreviation | `"ENE"` | @@ -123,7 +124,7 @@ MoonPosition structure (Exists only if latitude and longitude are specified): ---------------------------------------------------------------- -#### MoonDaysDetailed +##### MoonDaysDetailed ```MoonDaysDetailed``` is a structure that contains an array for each lunar day that falls on a given Earth day. Exists only if latitude and longitude are specified. @@ -143,7 +144,7 @@ MoonPosition structure (Exists only if latitude and longitude are specified): ---------------------------------------------------------------- -#### ZodiacDetailed +##### ZodiacDetailed ```ZodiacDetailed``` is a structure for determining which zodiac sign the moon is in on a given time interval, when it began and ended. It contains an array for each lunar day that falls on a given Earth day. @@ -164,7 +165,7 @@ MoonPosition structure (Exists only if latitude and longitude are specified): ---------------------------------------------------------------- -#### MoonRiseAndSet +##### MoonRiseAndSet ```MoonRiseAndSet``` is a structure for determining the moonrise, moonset and meridian on a given day. Exists only if latitude and longitude are specified. @@ -173,12 +174,13 @@ MoonPosition structure (Exists only if latitude and longitude are specified): | Response Variable | Type | Description | Example Value | | :--- | :--- | :--- | :--- | -|`MoonRiseAndSet.Moonrise` | `Object of struct MoonPosition [optional]` | Moonrise position data. Exists only if IsMoonRise = true | - | -|`MoonRiseAndSet.Moonset` | `Object of struct MoonPosition [optional]` | Moonset position data. Exists only if IsMoonSet = true | - | -|`MoonRiseAndSet.Meridian` | `Object of struct MoonPosition [optional]` | Meridian position data, Exists only if IsMeridian = true | - | +|`MoonRiseAndSet.Date` | `String [optional]` | Date for day of calculations, missing as default | `2025-01-15` | |`MoonRiseAndSet.IsMoonRise` | `Boolean [required]` | True if moonrise occurs at given day | `true` | |`MoonRiseAndSet.IsMoonSet` | `Boolean [required]` | True if moonset occurs at given day | `true` | |`MoonRiseAndSet.IsMeridian` | `Boolean [required]` | True if meridian transit occurs at given day | `true` | +|`MoonRiseAndSet.Moonrise` | `Object of struct MoonPosition [optional]` | Moonrise position data. Exists only if IsMoonRise = true | - | +|`MoonRiseAndSet.Moonset` | `Object of struct MoonPosition [optional]` | Moonset position data. Exists only if IsMoonSet = true | - | +|`MoonRiseAndSet.Meridian` | `Object of struct MoonPosition [optional]` | Meridian position data, Exists only if IsMeridian = true | - | MoonPosition structure: @@ -187,8 +189,7 @@ MoonPosition structure: | Response Variable | Type | Description | Example Value | | :--- | :--- | :--- | :--- | -|`MoonPosition.Timestamp` | `Integer [required]` | Moonrise Unix timestamp | `1758048970` | -|`MoonPosition.TimeISO` | `String [required]` | Moonrise ISO time | `"2025-09-16T23:56:10+05:00"` | +|`MoonPosition.Time` | `String / int64 [required]` | Time in ISO (default) or specified timeFormat | `"2025-09-16T00:00:00+05:00"` | |`MoonPosition.AzimuthDegrees` | `Float [required]` | Moonrise azimuth | `47.3` | |`MoonPosition.AltitudeDegrees` | `Float [required]` | Moonrise altitude | `-0.6` | |`MoonPosition.Direction` | `String [required]` | Moonrise direction | `"ENE"` | @@ -200,10 +201,10 @@ MoonPosition structure: ---------------------------------------------------------------- -#### Full response example: +#### Response examples Response of: -```GET /v1/moonPhaseDate?lang=ru&utc=5&latitude=51.1655&longitude=71.4272&year=2025&month=09&day=15&precision=5&hour=12&minute=0&second=0``` +```GET /api/v1/moonPhaseDate?lang=ru&utc=5&latitude=51.1655&longitude=71.4272&year=2025&month=09&day=15&precision=5&hour=12&minute=0&second=0```
JSON @@ -225,8 +226,7 @@ Response of: "Emoji": "♊" }, "MoonPosition": { - "Timestamp": 1757883600, - "TimeISO": "2025-09-15T02:00:00+05:00", + "Time": "2025-09-15T02:00:00+05:00", "AzimuthDegrees": 66.96877, "AltitudeDegrees": 17.50543, "Direction": "ENE", @@ -248,8 +248,7 @@ Response of: "Emoji": "♊" }, "MoonPosition": { - "Timestamp": 1757926800, - "TimeISO": "2025-09-15T14:00:00+05:00", + "Time": "2025-09-15T14:00:00+05:00", "AzimuthDegrees": 279.37345, "AltitudeDegrees": 29.04833, "Direction": "W", @@ -271,8 +270,7 @@ Response of: "Emoji": "♊" }, "MoonPosition": { - "Timestamp": 1757970000, - "TimeISO": "2025-09-16T02:00:00+05:00", + "Time": "2025-09-16T02:00:00+05:00", "AzimuthDegrees": 57.08873, "AltitudeDegrees": 8.79646, "Direction": "ENE", @@ -309,48 +307,308 @@ Response of: ] }, "MoonRiseAndSet": { + "IsMoonRise": true, + "IsMoonSet": true, + "IsMeridian": true, "Moonrise": { - "Timestamp": 1757957865, - "TimeISO": "2025-09-15T22:37:45+05:00", + "Time": "2025-09-15T22:37:45+05:00", "AzimuthDegrees": 42.31555, "AltitudeDegrees": -0.56667, "Direction": "NE", "DistanceKm": 376365.00012 }, "Moonset": { - "Timestamp": 1757933213, - "TimeISO": "2025-09-15T15:46:53+05:00", + "Time": "2025-09-15T15:46:53+05:00", "AzimuthDegrees": 318.44328, "AltitudeDegrees": -0.56667, "Direction": "NW", "DistanceKm": 375398.22022 }, "Meridian": { - "Timestamp": 1757900413, - "TimeISO": "2025-09-15T06:40:13+05:00", + "Time": "2025-09-15T06:40:13+05:00", "AzimuthDegrees": 180, "AltitudeDegrees": 67.1, "Direction": "S", "DistanceKm": 374133.37617 - }, - "IsMoonRise": true, - "IsMoonSet": true, - "IsMeridian": true + } } } ```
+ +
+ timeFormat = 2006-01-02 15:04 + +```json +{ + "BeginDay": { + "MoonDays": 0.85568, + "Illumination": 0.35744, + "Phase": { + "Name": "New Moon", + "NameLocalized": "Новолуние", + "Emoji": "🌑", + "IsWaxing": true + }, + "Zodiac": { + "Name": "Virgo", + "NameLocalized": "Дева", + "Emoji": "♍" + }, + "MoonPosition": { + "Time": "2025-01-01 00:00", + "AzimuthDegrees": 326.86255, + "AltitudeDegrees": -62.68617, + "Direction": "NNW", + "DistanceKm": 382464.56722 + } + }, + "CurrentState": { + "MoonDays": 0.89806, + "Illumination": 0.4137, + "Phase": { + "Name": "New Moon", + "NameLocalized": "Новолуние", + "Emoji": "🌑", + "IsWaxing": true + }, + "Zodiac": { + "Name": "Virgo", + "NameLocalized": "Дева", + "Emoji": "♍" + }, + "MoonPosition": { + "Time": "2025-01-01 01:01", + "AzimuthDegrees": 356.08557, + "AltitudeDegrees": -65.49632, + "Direction": "N", + "DistanceKm": 382316.55173 + } + }, + "EndDay": { + "MoonDays": 1.85568, + "Illumination": 2.79491, + "Phase": { + "Name": "New Moon", + "NameLocalized": "Новолуние", + "Emoji": "🌑", + "IsWaxing": true + }, + "Zodiac": { + "Name": "Virgo", + "NameLocalized": "Дева", + "Emoji": "♍" + }, + "MoonPosition": { + "Time": "2025-01-02 00:00", + "AzimuthDegrees": 309.21002, + "AltitudeDegrees": -54.25535, + "Direction": "NW", + "DistanceKm": 379194.7976 + } + }, + "MoonDaysDetailed": { + "Count": 2, + "Day": [ + { + "Begin": "2024-12-31 09:18", + "IsBeginExists": true, + "End": "2025-01-01 09:55", + "IsEndExists": true + }, + { + "Begin": "2025-01-01 09:55", + "IsBeginExists": true, + "End": "2025-01-02 10:21", + "IsEndExists": true + } + ] + }, + "ZodiacDetailed": { + "Count": 1, + "Zodiac": [ + { + "Name": "Virgo", + "NameLocalized": "Дева", + "Emoji": "♍", + "Begin": "2024-12-31 03:27", + "End": "2025-01-02 15:27" + } + ] + }, + "MoonRiseAndSet": { + "IsMoonRise": true, + "IsMoonSet": true, + "IsMeridian": true, + "Moonrise": { + "Time": "2025-01-01 09:55", + "AzimuthDegrees": 133.52155, + "AltitudeDegrees": -0.56667, + "Direction": "SE", + "DistanceKm": 381054.53085 + }, + "Moonset": { + "Time": "2025-01-01 17:26", + "AzimuthDegrees": 228.55471, + "AltitudeDegrees": -0.56667, + "Direction": "SW", + "DistanceKm": 380040.1844 + }, + "Meridian": { + "Time": "2025-01-01 13:36", + "AzimuthDegrees": 180, + "AltitudeDegrees": 13.2, + "Direction": "S", + "DistanceKm": 380550.46947 + } + } +} +``` + +
+ +
+ timeFormat = timestamp + +```json +{ + "BeginDay": { + "MoonDays": 0.85568, + "Illumination": 0.35744, + "Phase": { + "Name": "New Moon", + "NameLocalized": "Новолуние", + "Emoji": "🌑", + "IsWaxing": true + }, + "Zodiac": { + "Name": "Virgo", + "NameLocalized": "Дева", + "Emoji": "♍" + }, + "MoonPosition": { + "Time": 1735671600, + "AzimuthDegrees": 326.86255, + "AltitudeDegrees": -62.68617, + "Direction": "NNW", + "DistanceKm": 382464.56722 + } + }, + "CurrentState": { + "MoonDays": 0.89806, + "Illumination": 0.4137, + "Phase": { + "Name": "New Moon", + "NameLocalized": "Новолуние", + "Emoji": "🌑", + "IsWaxing": true + }, + "Zodiac": { + "Name": "Virgo", + "NameLocalized": "Дева", + "Emoji": "♍" + }, + "MoonPosition": { + "Time": 1735675261, + "AzimuthDegrees": 356.08557, + "AltitudeDegrees": -65.49632, + "Direction": "N", + "DistanceKm": 382316.55173 + } + }, + "EndDay": { + "MoonDays": 1.85568, + "Illumination": 2.79491, + "Phase": { + "Name": "New Moon", + "NameLocalized": "Новолуние", + "Emoji": "🌑", + "IsWaxing": true + }, + "Zodiac": { + "Name": "Virgo", + "NameLocalized": "Дева", + "Emoji": "♍" + }, + "MoonPosition": { + "Time": 1735758000, + "AzimuthDegrees": 309.21002, + "AltitudeDegrees": -54.25535, + "Direction": "NW", + "DistanceKm": 379194.7976 + } + }, + "MoonDaysDetailed": { + "Count": 2, + "Day": [ + { + "Begin": 1735618722, + "IsBeginExists": true, + "End": 1735707321, + "IsEndExists": true + }, + { + "Begin": 1735707321, + "IsBeginExists": true, + "End": 1735795276, + "IsEndExists": true + } + ] + }, + "ZodiacDetailed": { + "Count": 1, + "Zodiac": [ + { + "Name": "Virgo", + "NameLocalized": "Дева", + "Emoji": "♍", + "Begin": 1735597669, + "End": 1735813669 + } + ] + }, + "MoonRiseAndSet": { + "IsMoonRise": true, + "IsMoonSet": true, + "IsMeridian": true, + "Moonrise": { + "Time": 1735707321, + "AzimuthDegrees": 133.52155, + "AltitudeDegrees": -0.56667, + "Direction": "SE", + "DistanceKm": 381054.53085 + }, + "Moonset": { + "Time": 1735734376, + "AzimuthDegrees": 228.55471, + "AltitudeDegrees": -0.56667, + "Direction": "SW", + "DistanceKm": 380040.1844 + }, + "Meridian": { + "Time": 1735720605, + "AzimuthDegrees": 180, + "AltitudeDegrees": 13.2, + "Direction": "S", + "DistanceKm": 380550.46947 + } + } +} +``` + +
+ ---------------------------------------------------------------- -### GET /v1/moonPhaseCurrent +### GET /api/v1/moonPhaseCurrent The method returns the Moon parameters for the current day and time. If the day or time is not specified, the current value for the unspecified fields is taken. If longitude and latitude are specified, the response will contain additional structures. This is a synonym for the moonPhaseDate method without day and time Params. -### Params +#### Params | Parameter | Type | Description | Example Value | | :--- | :--- | :--- | :--- | @@ -359,20 +617,21 @@ This is a synonym for the moonPhaseDate method without day and time Params. |`precision` | `int [optional, default=2]` | How many digits after ```.``` will be in output. Allowed range: [1, 20] | `5` |`latitude` | `float [optional, default=none]` | Latitude of viewer's place. Used for moon position calculations: ```MoonDaysDetailed```, ```MoonRiseAndSet```, and ```MoonPosition``` object | `51.1655` |`longitude` | `float [optional, default=none]` | Longitude of viewer's place. Used for moon position calculations: ```MoonDaysDetailed```, ```MoonRiseAndSet```, and ```MoonPosition``` object | `71.4272` +|`timeFormat` | `string [optional]` | How the data will be formed. Available values: ISO (default), timestamp, duration or Go format. Duration is seconds between current date and event time.| `duration` -### Response +#### Response -Response as [GET /v1/moonPhaseDate](https://github.com/prostraction/moon/#v1moonphasedate-response) +Response as [GET /api/v1/moonPhaseDate](https://github.com/prostraction/moon/#v1moonphasedate-response) ---------------------------------------------------------------- -### GET /v1/moonPhaseTimestamp +### GET /api/v1/moonPhaseTimestamp The method returns the Moon parameters for the given timestamp. If it is not specified, the current value for the timestamp is taken. If longitude and latitude are specified, the response will contain additional structures. This is a synonym for the moonPhaseDate method but with timestamp instead of date. -### Params +#### Params | Parameter | Type | Description | Example Value | | :--- | :--- | :--- | :--- | @@ -382,25 +641,254 @@ This is a synonym for the moonPhaseDate method but with timestamp instead of dat |`latitude` | `float [optional, default=none]` | Latitude of viewer's place. Used for moon position calculations: ```MoonDaysDetailed```, ```MoonRiseAndSet```, and ```MoonPosition``` object | `51.1655` |`longitude` | `float [optional, default=none]` | Longitude of viewer's place. Used for moon position calculations: ```MoonDaysDetailed```, ```MoonRiseAndSet```, and ```MoonPosition``` object | `71.4272` |`timestamp` | `int [optional, default=]` | Timestamp for calculations | `1758045697` +|`timeFormat` | `string [optional]` | How the data will be formed. Available values: ISO (default), timestamp, duration or Go format. Duration is seconds between current date and event time.| `duration` + +#### Response + +Response as [GET /api/v1/moonPhaseDate](https://github.com/prostraction/moon/#v1moonphasedate-response) + +---------------------------------------------------------------- + +### GET /api/v1/moonPositionMonthly + +The method returns Moon position for specified month. + +#### Params + + | Parameter | Type | Description | Example Value | +| :--- | :--- | :--- | :--- | +|`utc` | `string [optional, default="UTC+0"]` | UTC in format `UTC+7`, `UTC+09:30`, `-3` | `UTC+4` +|`precision` | `int [optional, default=2]` | How many digits after ```.``` will be in output. Allowed range: [1, 20] | `5` +|`latitude` | `float [required]` | Latitude of viewer's place. Used for moon position calculations: ```MoonDaysDetailed```, ```MoonRiseAndSet```, and ```MoonPosition``` object | `51.1655` +|`longitude` | `float [required]` | Longitude of viewer's place. Used for moon position calculations: ```MoonDaysDetailed```, ```MoonRiseAndSet```, and ```MoonPosition``` object | `71.4272` +|`year` | `int [optional, default=]` | Format: YYYY Allowed range: [1, 9999] | `2025` +|`month` | `int [optional, default=]` | Format: M or MM. Allowed range: [1, 12] | `01` or `1` +|`timeFormat` | `string [optional]` | How the data will be formed. Available values: ISO (default), timestamp, duration or Go format. Duration is seconds between current date and event time.| `duration` + +#### Response + +The method returns array of object MoonRiseAndSet for each day of selected month. + +##### MoonRiseAndSet + +```MoonRiseAndSet``` is a structure for determining the moonrise, moonset and meridian on a given day. Exists only if latitude and longitude are specified. + +
+ Table + +| Response Variable | Type | Description | Example Value | +| :--- | :--- | :--- | :--- | +|`MoonRiseAndSet.Date` | `String [optional]` | Date for day of calculations, missing as default | `2025-01-15` | +|`MoonRiseAndSet.IsMoonRise` | `Boolean [required]` | True if moonrise occurs at given day | `true` | +|`MoonRiseAndSet.IsMoonSet` | `Boolean [required]` | True if moonset occurs at given day | `true` | +|`MoonRiseAndSet.IsMeridian` | `Boolean [required]` | True if meridian transit occurs at given day | `true` | +|`MoonRiseAndSet.Moonrise` | `Object of struct MoonPosition [optional]` | Moonrise position data. Exists only if IsMoonRise = true | - | +|`MoonRiseAndSet.Moonset` | `Object of struct MoonPosition [optional]` | Moonset position data. Exists only if IsMoonSet = true | - | +|`MoonRiseAndSet.Meridian` | `Object of struct MoonPosition [optional]` | Meridian position data, Exists only if IsMeridian = true | - | + +MoonPosition structure: + +
+ Table + +| Response Variable | Type | Description | Example Value | +| :--- | :--- | :--- | :--- | +|`MoonPosition.Time` | `String / int64 [required]` | Time in ISO (default) or specified timeFormat | `"2025-09-16T00:00:00+05:00"` | +|`MoonPosition.AzimuthDegrees` | `Float [required]` | Moonrise azimuth | `47.3` | +|`MoonPosition.AltitudeDegrees` | `Float [required]` | Moonrise altitude | `-0.6` | +|`MoonPosition.Direction` | `String [required]` | Moonrise direction | `"ENE"` | +|`MoonPosition.DistanceKm` | `Float [required]` | Earth-Moon distance in km | `376559.9` | + +
+ +
+ +#### Response example + +
+ JSON + +```json +[ + { + "Date": "2023-03-01", + "IsMoonRise": true, + "IsMoonSet": true, + "IsMeridian": true, + "Moonrise": { + "Time": "2023-03-01T11:07:37+05:00", + "AzimuthDegrees": 42.8762, + "AltitudeDegrees": -0.56667, + "Direction": "NE", + "DistanceKm": 402636.75966 + }, + "Moonset": { + "Time": "2023-03-01T04:10:07+05:00", + "AzimuthDegrees": 316.74613, + "AltitudeDegrees": -0.56667, + "Direction": "NW", + "DistanceKm": 401798.89266 + }, + "Meridian": { + "Time": "2023-03-01T20:05:30+05:00", + "AzimuthDegrees": 180, + "AltitudeDegrees": 66.2, + "Direction": "S", + "DistanceKm": 403572.05151 + } + }, + { + "Date": "2023-03-02", + "IsMoonRise": true, + "IsMoonSet": true, + "IsMeridian": true, + "Moonrise": { + "Time": "2023-03-02T12:01:07+05:00", + "AzimuthDegrees": 43.38104, + "AltitudeDegrees": -0.56667, + "Direction": "NE", + "DistanceKm": 404836.13007 + }, + "Moonset": { + "Time": "2023-03-02T05:03:00+05:00", + "AzimuthDegrees": 317.04922, + "AltitudeDegrees": -0.56667, + "Direction": "NW", + "DistanceKm": 404345.126 + }, + "Meridian": { + "Time": "2023-03-02T20:56:36+05:00", + "AzimuthDegrees": 180, + "AltitudeDegrees": 65.4, + "Direction": "S", + "DistanceKm": 405326.66664 + } + }, + ... + { + "Date": "2023-03-31", + "IsMoonRise": true, + "IsMoonSet": true, + "IsMeridian": true, + "Moonrise": { + "Time": "2023-03-31T11:58:33+05:00", + "AzimuthDegrees": 49.55137, + "AltitudeDegrees": -0.56667, + "Direction": "NE", + "DistanceKm": 404935.96867 + }, + "Moonset": { + "Time": "2023-03-31T04:17:06+05:00", + "AzimuthDegrees": 312.1322, + "AltitudeDegrees": -0.56667, + "Direction": "NW", + "DistanceKm": 404804.48186 + }, + "Meridian": { + "Time": "2023-03-31T20:28:24+05:00", + "AzimuthDegrees": 180, + "AltitudeDegrees": 61.6, + "Direction": "S", + "DistanceKm": 404936.05398 + } + } +] +``` + +
-### Response +
+ timeFormat '2006-01-02 15:04' + +```json +[ + { + "Date": "2023-03-01", + "IsMoonRise": true, + "IsMoonSet": true, + "IsMeridian": true, + "Moonrise": { + "Time": "2023-03-01 11:07", + "AzimuthDegrees": 42.8762, + "AltitudeDegrees": -0.56667, + "Direction": "NE", + "DistanceKm": 402636.75966 + }, + "Moonset": { + "Time": "2023-03-01 04:10", + "AzimuthDegrees": 316.74613, + "AltitudeDegrees": -0.56667, + "Direction": "NW", + "DistanceKm": 401798.89266 + }, + "Meridian": { + "Time": "2023-03-01 20:05", + "AzimuthDegrees": 180, + "AltitudeDegrees": 66.2, + "Direction": "S", + "DistanceKm": 403572.05151 + } + }, + ... +``` + +
-Response as [GET /v1/moonPhaseDate](https://github.com/prostraction/moon/#v1moonphasedate-response) + +
+ timeFormat 'timestamp' + +```json +[ + { + "Date": "2023-03-01", + "IsMoonRise": true, + "IsMoonSet": true, + "IsMeridian": true, + "Moonrise": { + "Time": 1677650857, + "AzimuthDegrees": 42.8762, + "AltitudeDegrees": -0.56667, + "Direction": "NE", + "DistanceKm": 402636.75966 + }, + "Moonset": { + "Time": 1677625807, + "AzimuthDegrees": 316.74613, + "AltitudeDegrees": -0.56667, + "Direction": "NW", + "DistanceKm": 401798.89266 + }, + "Meridian": { + "Time": 1677683130, + "AzimuthDegrees": 180, + "AltitudeDegrees": 66.2, + "Direction": "S", + "DistanceKm": 403572.05151 + } + }, + ... +``` +
---------------------------------------------------------------- -### GET /v1/moonTableYear +### GET /api/v1/moonTableYear The method returns the moon phases for the given year. The response contains an array for each month, each element of which contains the time of the new moon, first quarter, full moon, last quarter. -### Params +#### Params | Parameter | Type | Description | Example Value | | :--- | :--- | :--- | :--- | |`utc` | `string [optional, default="UTC+0"]` | UTC in format `UTC+7`, `UTC+09:30`, `-3` | `UTC+4` |`year` | `int [optional, default=]` | Format: YYYY Allowed range: [1, 9999] | `2025` +|`timeFormat` | `string [optional]` | How the data will be formed. Available values: ISO (default), timestamp, duration or Go format. Duration is seconds between current date and event time.| `duration` -### /v1/moonTableYear Response +#### Response example + +
+ JSON ```json [ @@ -429,18 +917,270 @@ The method returns the moon phases for the given year. The response contains an ] ``` +
+ +
+ timeFormat '2006-01-02 15:04' + +```json +[ + // first moon of the year + { + "NewMoon": "2022-12-23 15:17", + "FirstQuarter": "2022-12-30 06:24", + "FullMoon": "2023-01-07 04:09", + "LastQuarter": "2023-01-07 04:09" + }, + // second moon of the year + { + "NewMoon": "2023-01-22 01:55", + "FirstQuarter": "2023-01-28 20:05", + "FullMoon": "2023-02-05 23:30", + "LastQuarter": "2023-02-05 23:30" + }, +... + // last moon of the year + { + "NewMoon": "2023-12-13 04:32", + "FirstQuarter": "2023-12-19 23:42", + "FullMoon": "2023-12-27 05:33", + "LastQuarter": "2023-12-27 05:33" + } +] +``` + +
+ +
+ timeFormat 'timestamp' + +```json +[ + // first moon of the year + { + "NewMoon": 1671790676, + "FirstQuarter": 1672363444, + "FullMoon": 1673046595, + "LastQuarter": 1673046595 + }, + // second moon of the year + { + "NewMoon": 1674334530, + "FirstQuarter": 1674918315, + "FullMoon": 1675621844, + "LastQuarter": 1675621844 + }, +... + // last moon of the year + { + "NewMoon": 1702423927, + "FirstQuarter": 1703011321, + "FullMoon": 1703637223, + "LastQuarter": 1703637223 + } +] +``` + +
+ ---------------------------------------------------------------- -### GET /v1/moonTableCurrent +### GET /api/v1/moonTableCurrent The method returns the moon phases for the current year. The response contains an array for each month, each element of which contains the time of the new moon, first quarter, full moon, last quarter. -### Params +#### Params | Parameter | Type | Description | Example Value | | :--- | :--- | :--- | :--- | |`utc` | `string [optional, default="UTC+0"]` | UTC in format `UTC+7`, `UTC+09:30`, `-3` | `UTC+4` +|`timeFormat` | `string [optional]` | How the data will be formed. Available values: ISO (default), timestamp, duration or Go format. Duration is seconds between current date and event time.| `duration` + +#### Response + +Response: as [GET /api/v1/moonTableYear](https://github.com/prostraction/moon#v1moontableyear-response) + +---------------------------------------------------------------- + +### GET /api/v1/toJulianTimeByDate + +The method converts human date to julian time (UTC +0 timezone). + +#### Params + + | Parameter | Type | Description | Example Value | +| :--- | :--- | :--- | :--- | +|`precision` | `int [optional, default=2]` | How many digits after ```.``` will be in output. Allowed range: [1, 20] | `5` +|`timeFormat` | `string [optional]` | How the data will be formed. Available values: ISO (default), timestamp, duration or Go format. Duration is seconds between current date and event time.| `duration` +|`year` | `int [optional, default=]` | Format: YYYY Allowed range: [1, 9999] | `2025` +|`month` | `int [optional, default=]` | Format: M or MM. Allowed range: [1, 12] | `01` or `1` +|`day` | `int [optional, default=]` | Format: D or DD. Allowed range: [1, 31] | `01` or `1` +|`hour` | `int [optional, default=]` | Format: h or hh. Allowed range: [0, 23] | `01` or `1` +|`minute` | `int [optional, default=]` | Format: m or mm. Allowed range: [0, 59] | `01` or `1` +|`second` | `int [optional, default=]` | Format: s or ss. Allowed range: [0, 59] | `01` or `1` + +#### Response examples + +```json +{ + "CivilDate": "2025-01-01T01:01:01Z", + "JulianDate": 2460676.54237 +} +``` + +timeFormat: `Mon, 02 Jan 2006 15:04:05` + +```json +{ + "CivilDate": "Wed, 01 Jan 2025 01:01:01", + "JulianDate": 2460676.54237 +} +``` -### Response: +timeFormat: `timestamp` -Response: as GET [/v1/moonTableYear](https://github.com/prostraction/moon#v1moontableyear-response) +```json +{ + "CivilDate": 1735693261, + "JulianDate": 2460676.54237 +} +``` + +---------------------------------------------------------------- + +### GET /api/v1/toJulianTimeByTimestamp + +The method converts human date to julian time (UTC +0 timezone). + +#### Params + + | Parameter | Type | Description | Example Value | +| :--- | :--- | :--- | :--- | +|`precision` | `int [optional, default=2]` | How many digits after ```.``` will be in output. Allowed range: [1, 20] | `5` +|`timestamp` | `int [optional, default=]` | Timestamp for calculations. Current, if not specified | `1735693261` +|`timeFormat` | `string [optional]` | How the data will be formed. Available values: ISO (default), timestamp, duration or Go format. Duration is seconds between current date and event time.| `duration` + +#### Response example + +```json +{ + "CivilDate": "2025-01-01T01:01:01Z", + "JulianDate": 2460676.54237 +} +``` + +timeFormat: `Mon, 02 Jan 2006 15:04:05` + +```json +{ + "CivilDate": "Wed, 01 Jan 2025 01:01:01", + "JulianDate": 2460676.54237 +} +``` + +timeFormat: `timestamp` + +```json +{ + "CivilDate": 1735693261, + "JulianDate": 2460676.54237 +} + +---------------------------------------------------------------- + +### GET /api/v1/fromJulianTime + +The method converts julian time to human time (UTC +0 timezone). + +#### Params + + | Parameter | Type | Description | Example Value | +| :--- | :--- | :--- | :--- | +|`precision` | `int [optional, default=2]` | How many digits after ```.``` will be in output. Allowed range: [1, 20] | `5` +|`jtime` | `float64 [required]` | Julian Time to convert (float64) | `2460676.5423726854` +|`timeFormat` | `string [optional]` | How the data will be formed. Available values: ISO (default), timestamp, duration or Go format. Duration is seconds between current date and event time.| `duration` + +#### Response examples + +```json +{ + "CivilDate": "2025-01-01T01:01:01Z", + "JulianDate": 2460676.54237 +} +``` + +timeFormat: `Mon, 02 Jan 2006 15:04:05` + +```json +{ + "CivilDate": "Wed, 01 Jan 2025 01:01:01", + "JulianDate": 2460676.54237 +} +``` + +timeFormat: `timestamp` + +```json +{ + "CivilDate": 1735693261, + "JulianDate": 2460676.54237 +} +``` + +### GET /api/v1/nextMoonPhase + +The method returns next moon phase + +#### Params + + | Parameter | Type | Description | Example Value | +| :--- | :--- | :--- | :--- | +|`utc` | `string [optional, default="UTC+0"]` | UTC in format `UTC+7`, `UTC+09:30`, `-3` | `UTC+4` +|`timeFormat` | `string [optional]` | How the data will be formed. Available values: ISO (default), timestamp, duration or Go format. Duration is seconds between current date and event time.| `duration` + + +#### Response example: + +timeFormat: `ISO` + +```json +{ + "NewMoon": "2025-11-20T11:48:16+05:00", + "FirstQuarter": "2025-11-28T11:44:00+05:00", + "FullMoon": "2025-12-05T04:15:18+05:00", + "LastQuarter": "2025-12-12T02:04:31+05:00" +} +``` + +timeFormat: `Mon, 02 Jan 2006 15:04:05` + +```json +{ + "NewMoon": "Thu, 20 Nov 2025 11:48:16", + "FirstQuarter": "Fri, 28 Nov 2025 11:44:00", + "FullMoon": "Fri, 05 Dec 2025 04:15:18", + "LastQuarter": "Fri, 12 Dec 2025 02:04:31" +} +``` + +timeFormat: `timestamp` + +```json +{ + "NewMoon": 1763621296, + "FirstQuarter": 1764312240, + "FullMoon": 1764890118, + "LastQuarter": 1765487071 +} +``` + +timeFormat: `duration` + +```json +{ + "NewMoon": 313830, + "FirstQuarter": 1004774, + "FullMoon": 1582652, + "LastQuarter": 2179605 +} +``` \ No newline at end of file diff --git a/doc/postman_collection b/doc/postman_collection index 9badfd6..dea4ad2 100644 --- a/doc/postman_collection +++ b/doc/postman_collection @@ -1,13 +1,13 @@ { "info": { - "_postman_id": "9d158224-dba6-4890-ad63-22f987406d00", + "_postman_id": "026b2bd4-85f5-43d9-8f57-f1d26a4e548a", "name": "Moon Collection V1", "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", - "_exporter_id": "19971618" + "_exporter_id": "37785427" }, "item": [ { - "name": "Moon Phase — Detailed information for day", + "name": "Moon Phase — Detailed information for day (phase, rise, zodiac)", "item": [ { "name": "Get moon plase by specified date", @@ -15,7 +15,7 @@ "method": "GET", "header": [], "url": { - "raw": "{{baseUrl}}/v1/moonPhaseDate?utc=UTC+5&lang=ru&precision=5&latitude=51.1655&longitude=71.4272&year=2025&month=01&day=01&hour=01&minute=01&second=01", + "raw": "{{baseUrl}}/v1/moonPhaseDate?utc=UTC+5&lang=ru&precision=5&latitude=51.1655&longitude=71.4272&year=2025&month=01&day=01&hour=01&minute=01&second=01&timeFormat=2006-01-02 15:04", "host": [ "{{baseUrl}}" ], @@ -52,32 +52,37 @@ { "key": "year", "value": "2025", - "description": "Format: YYYY Allowed range: [1, 9999]" + "description": "Format: YYYY Allowed range: [1, 9999]. Current, if not specified" }, { "key": "month", "value": "01", - "description": "Format: M or MM. Allowed range: [1, 12]" + "description": "Format: M or MM. Allowed range: [1, 12]. Current, if not specified" }, { "key": "day", "value": "01", - "description": "Format: D or DD. Allowed range: [1, 31]" + "description": "Format: D or DD. Allowed range: [1, 31]. Current, if not specified" }, { "key": "hour", "value": "01", - "description": "Format: h or hh. Allowed range: [0, 23]" + "description": "Format: h or hh. Allowed range: [0, 23]. Current, if not specified" }, { "key": "minute", "value": "01", - "description": "Format: m or mm. Allowed range: [0, 59]" + "description": "Format: m or mm. Allowed range: [0, 59]. Current, if not specified" }, { "key": "second", "value": "01", - "description": "Format: s or ss. Allowed range: [0, 59]" + "description": "Format: s or ss. Allowed range: [0, 59]. Current, if not specified" + }, + { + "key": "timeFormat", + "value": "2006-01-02 15:04", + "description": "Supports: \"ISO\" (default), \"timestamp\" any Go time format directives (without UTC), for example: \"Mon, 02 Jan 2006 15:04:05\"" } ] }, @@ -127,32 +132,32 @@ { "key": "year", "value": "2025", - "description": "Format: YYYY Allowed range: [1, 9999]" + "description": "Format: YYYY Allowed range: [1, 9999]. Current, if not specified" }, { "key": "month", "value": "01", - "description": "Format: M or MM. Allowed range: [1, 12]" + "description": "Format: M or MM. Allowed range: [1, 12]. Current, if not specified" }, { "key": "day", "value": "01", - "description": "Format: D or DD. Allowed range: [1, 31]" + "description": "Format: D or DD. Allowed range: [1, 31]. Current, if not specified" }, { "key": "hour", "value": "01", - "description": "Format: h or hh. Allowed range: [0, 23]" + "description": "Format: h or hh. Allowed range: [0, 23]. Current, if not specified" }, { "key": "minute", "value": "01", - "description": "Format: m or mm. Allowed range: [0, 59]" + "description": "Format: m or mm. Allowed range: [0, 59]. Current, if not specified" }, { "key": "second", "value": "01", - "description": "Format: s or ss. Allowed range: [0, 59]" + "description": "Format: s or ss. Allowed range: [0, 59]. Current, if not specified" } ] } @@ -189,68 +194,126 @@ } ], "cookie": [], - "body": "{\n \"BeginDay\": {\n \"MoonDays\": 0.85568,\n \"Illumination\": 0.35744,\n \"Phase\": {\n \"Name\": \"New Moon\",\n \"NameLocalized\": \"Новолуние\",\n \"Emoji\": \"🌑\",\n \"IsWaxing\": true\n },\n \"Zodiac\": {\n \"Name\": \"Virgo\",\n \"NameLocalized\": \"Дева\",\n \"Emoji\": \"♍\"\n },\n \"MoonPosition\": {\n \"Timestamp\": 1735671600,\n \"TimeISO\": \"2025-01-01T00:00:00+05:00\",\n \"AzimuthDegrees\": 326.86255,\n \"AltitudeDegrees\": -62.68617,\n \"Direction\": \"NNW\",\n \"DistanceKm\": 382464.56722\n }\n },\n \"CurrentState\": {\n \"MoonDays\": 0.89806,\n \"Illumination\": 0.4137,\n \"Phase\": {\n \"Name\": \"New Moon\",\n \"NameLocalized\": \"Новолуние\",\n \"Emoji\": \"🌑\",\n \"IsWaxing\": true\n },\n \"Zodiac\": {\n \"Name\": \"Virgo\",\n \"NameLocalized\": \"Дева\",\n \"Emoji\": \"♍\"\n },\n \"MoonPosition\": {\n \"Timestamp\": 1735675261,\n \"TimeISO\": \"2025-01-01T01:01:01+05:00\",\n \"AzimuthDegrees\": 356.08557,\n \"AltitudeDegrees\": -65.49632,\n \"Direction\": \"N\",\n \"DistanceKm\": 382316.55173\n }\n },\n \"EndDay\": {\n \"MoonDays\": 1.85568,\n \"Illumination\": 2.79491,\n \"Phase\": {\n \"Name\": \"New Moon\",\n \"NameLocalized\": \"Новолуние\",\n \"Emoji\": \"🌑\",\n \"IsWaxing\": true\n },\n \"Zodiac\": {\n \"Name\": \"Virgo\",\n \"NameLocalized\": \"Дева\",\n \"Emoji\": \"♍\"\n },\n \"MoonPosition\": {\n \"Timestamp\": 1735758000,\n \"TimeISO\": \"2025-01-02T00:00:00+05:00\",\n \"AzimuthDegrees\": 309.21002,\n \"AltitudeDegrees\": -54.25535,\n \"Direction\": \"NW\",\n \"DistanceKm\": 379194.7976\n }\n },\n \"MoonDaysDetailed\": {\n \"Count\": 2,\n \"Day\": [\n {\n \"Begin\": \"2024-12-31T09:18:42+05:00\",\n \"IsBeginExists\": true,\n \"End\": \"2025-01-01T09:55:21+05:00\",\n \"IsEndExists\": true\n },\n {\n \"Begin\": \"2025-01-01T09:55:21+05:00\",\n \"IsBeginExists\": true,\n \"End\": \"2025-01-02T10:21:16+05:00\",\n \"IsEndExists\": true\n }\n ]\n },\n \"ZodiacDetailed\": {\n \"Count\": 1,\n \"Zodiac\": [\n {\n \"Name\": \"Virgo\",\n \"NameLocalized\": \"Дева\",\n \"Emoji\": \"♍\",\n \"Begin\": \"2024-12-31T03:27:49+05:00\",\n \"End\": \"2025-01-02T15:27:49+05:00\"\n }\n ]\n },\n \"MoonRiseAndSet\": {\n \"Moonrise\": {\n \"Timestamp\": 1735707321,\n \"TimeISO\": \"2025-01-01T09:55:21+05:00\",\n \"AzimuthDegrees\": 133.52155,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"SE\",\n \"DistanceKm\": 381054.53085\n },\n \"Moonset\": {\n \"Timestamp\": 1735734376,\n \"TimeISO\": \"2025-01-01T17:26:16+05:00\",\n \"AzimuthDegrees\": 228.55471,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"SW\",\n \"DistanceKm\": 380040.1844\n },\n \"Meridian\": {\n \"Timestamp\": 1735720605,\n \"TimeISO\": \"2025-01-01T13:36:45+05:00\",\n \"AzimuthDegrees\": 180,\n \"AltitudeDegrees\": 13.2,\n \"Direction\": \"S\",\n \"DistanceKm\": 380550.46947\n },\n \"IsMoonRise\": true,\n \"IsMoonSet\": true,\n \"IsMeridian\": true\n }\n}" - } - ] - }, - { - "name": "Get moon phase by current date", - "request": { - "method": "GET", - "header": [], - "url": { - "raw": "{{baseUrl}}/v1/moonPhaseCurrent?utc=UTC+5&lang=ru&precision=5&latitude=51.1655&longitude=71.4272", - "host": [ - "{{baseUrl}}" - ], - "path": [ - "v1", - "moonPhaseCurrent" - ], - "query": [ - { - "key": "utc", - "value": "UTC+5", - "description": "UTC in format UTC+7, UTC+09:30, -3" - }, + "body": "{\n \"BeginDay\": {\n \"MoonDays\": 0.85568,\n \"Illumination\": 0.35744,\n \"Phase\": {\n \"Name\": \"New Moon\",\n \"NameLocalized\": \"Новолуние\",\n \"Emoji\": \"🌑\",\n \"IsWaxing\": true\n },\n \"Zodiac\": {\n \"Name\": \"Virgo\",\n \"NameLocalized\": \"Дева\",\n \"Emoji\": \"♍\"\n },\n \"MoonPosition\": {\n \"Time\": \"2025-01-01T00:00:00+05:00\",\n \"AzimuthDegrees\": 326.86255,\n \"AltitudeDegrees\": -62.68617,\n \"Direction\": \"NNW\",\n \"DistanceKm\": 382464.56722\n }\n },\n \"CurrentState\": {\n \"MoonDays\": 0.89806,\n \"Illumination\": 0.4137,\n \"Phase\": {\n \"Name\": \"New Moon\",\n \"NameLocalized\": \"Новолуние\",\n \"Emoji\": \"🌑\",\n \"IsWaxing\": true\n },\n \"Zodiac\": {\n \"Name\": \"Virgo\",\n \"NameLocalized\": \"Дева\",\n \"Emoji\": \"♍\"\n },\n \"MoonPosition\": {\n \"Time\": \"2025-01-01T01:01:01+05:00\",\n \"AzimuthDegrees\": 356.08557,\n \"AltitudeDegrees\": -65.49632,\n \"Direction\": \"N\",\n \"DistanceKm\": 382316.55173\n }\n },\n \"EndDay\": {\n \"MoonDays\": 1.85568,\n \"Illumination\": 2.79491,\n \"Phase\": {\n \"Name\": \"New Moon\",\n \"NameLocalized\": \"Новолуние\",\n \"Emoji\": \"🌑\",\n \"IsWaxing\": true\n },\n \"Zodiac\": {\n \"Name\": \"Virgo\",\n \"NameLocalized\": \"Дева\",\n \"Emoji\": \"♍\"\n },\n \"MoonPosition\": {\n \"Time\": \"2025-01-02T00:00:00+05:00\",\n \"AzimuthDegrees\": 309.21002,\n \"AltitudeDegrees\": -54.25535,\n \"Direction\": \"NW\",\n \"DistanceKm\": 379194.7976\n }\n },\n \"MoonDaysDetailed\": {\n \"Count\": 2,\n \"Day\": [\n {\n \"Begin\": \"2024-12-31T09:18:42+05:00\",\n \"IsBeginExists\": true,\n \"End\": \"2025-01-01T09:55:21+05:00\",\n \"IsEndExists\": true\n },\n {\n \"Begin\": \"2025-01-01T09:55:21+05:00\",\n \"IsBeginExists\": true,\n \"End\": \"2025-01-02T10:21:16+05:00\",\n \"IsEndExists\": true\n }\n ]\n },\n \"ZodiacDetailed\": {\n \"Count\": 1,\n \"Zodiac\": [\n {\n \"Name\": \"Virgo\",\n \"NameLocalized\": \"Дева\",\n \"Emoji\": \"♍\",\n \"Begin\": \"2024-12-31T03:27:49+05:00\",\n \"End\": \"2025-01-02T15:27:49+05:00\"\n }\n ]\n },\n \"MoonRiseAndSet\": {\n \"IsMoonRise\": true,\n \"IsMoonSet\": true,\n \"IsMeridian\": true,\n \"Moonrise\": {\n \"Time\": \"2025-01-01T09:55:21+05:00\",\n \"AzimuthDegrees\": 133.52155,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"SE\",\n \"DistanceKm\": 381054.53085\n },\n \"Moonset\": {\n \"Time\": \"2025-01-01T17:26:16+05:00\",\n \"AzimuthDegrees\": 228.55471,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"SW\",\n \"DistanceKm\": 380040.1844\n },\n \"Meridian\": {\n \"Time\": \"2025-01-01T13:36:45+05:00\",\n \"AzimuthDegrees\": 180,\n \"AltitudeDegrees\": 13.2,\n \"Direction\": \"S\",\n \"DistanceKm\": 380550.46947\n }\n }\n}" + }, + { + "name": "moonPhaseDate — custom timeFormat", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/v1/moonPhaseDate?utc=UTC+5&lang=ru&precision=5&latitude=51.1655&longitude=71.4272&year=2025&month=01&day=01&hour=01&minute=01&second=01&timeFormat=2006-01-02 15:04", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "v1", + "moonPhaseDate" + ], + "query": [ + { + "key": "utc", + "value": "UTC+5", + "description": "UTC in format UTC+7, UTC+09:30, -3" + }, + { + "key": "lang", + "value": "ru", + "description": "Values available: (\"en\", \"es\", \"fr\", \"de\", \"ru\", \"jp\")" + }, + { + "key": "precision", + "value": "5", + "description": "How many digits after . will be in output. Allowed range: [1, 20]" + }, + { + "key": "latitude", + "value": "51.1655", + "description": "Latitude of viewer's place. Used for moon position calculations: MoonDaysDetailed, MoonRiseAndSet, and MoonPosition object" + }, + { + "key": "longitude", + "value": "71.4272", + "description": "Longitude of viewer's place. Used for moon position calculations: MoonDaysDetailed, MoonRiseAndSet, and MoonPosition object" + }, + { + "key": "year", + "value": "2025", + "description": "Format: YYYY Allowed range: [1, 9999]. Current, if not specified" + }, + { + "key": "month", + "value": "01", + "description": "Format: M or MM. Allowed range: [1, 12]. Current, if not specified" + }, + { + "key": "day", + "value": "01", + "description": "Format: D or DD. Allowed range: [1, 31]. Current, if not specified" + }, + { + "key": "hour", + "value": "01", + "description": "Format: h or hh. Allowed range: [0, 23]. Current, if not specified" + }, + { + "key": "minute", + "value": "01", + "description": "Format: m or mm. Allowed range: [0, 59]. Current, if not specified" + }, + { + "key": "second", + "value": "01", + "description": "Format: s or ss. Allowed range: [0, 59]. Current, if not specified" + }, + { + "key": "timeFormat", + "value": "2006-01-02 15:04", + "description": "Supports: \"ISO\" (default), \"timestamp\" any Go time format directives (without UTC), for example: \"Mon, 02 Jan 2006 15:04:05\"" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ { - "key": "lang", - "value": "ru", - "description": "Values available: (\"en\", \"es\", \"fr\", \"de\", \"ru\", \"jp\")" + "key": "Server", + "value": "Fiber" }, { - "key": "precision", - "value": "5", - "description": "How many digits after . will be in output. Allowed range: [1, 20]" + "key": "Date", + "value": "Sun, 16 Nov 2025 18:21:08 GMT" }, { - "key": "latitude", - "value": "51.1655", - "description": "Latitude of viewer's place. Used for moon position calculations: MoonDaysDetailed, MoonRiseAndSet, and MoonPosition object" + "key": "Content-Type", + "value": "application/json", + "name": "Content-Type", + "description": "", + "type": "text" }, { - "key": "longitude", - "value": "71.4272", - "description": "Longitude of viewer's place. Used for moon position calculations: MoonDaysDetailed, MoonRiseAndSet, and MoonPosition object" + "key": "Content-Length", + "value": "1922" } - ] + ], + "cookie": [], + "body": "{\n \"BeginDay\": {\n \"MoonDays\": 0.85568,\n \"Illumination\": 0.35744,\n \"Phase\": {\n \"Name\": \"New Moon\",\n \"NameLocalized\": \"Новолуние\",\n \"Emoji\": \"🌑\",\n \"IsWaxing\": true\n },\n \"Zodiac\": {\n \"Name\": \"Virgo\",\n \"NameLocalized\": \"Дева\",\n \"Emoji\": \"♍\"\n },\n \"MoonPosition\": {\n \"Time\": \"2025-01-01 00:00\",\n \"AzimuthDegrees\": 326.86255,\n \"AltitudeDegrees\": -62.68617,\n \"Direction\": \"NNW\",\n \"DistanceKm\": 382464.56722\n }\n },\n \"CurrentState\": {\n \"MoonDays\": 0.89806,\n \"Illumination\": 0.4137,\n \"Phase\": {\n \"Name\": \"New Moon\",\n \"NameLocalized\": \"Новолуние\",\n \"Emoji\": \"🌑\",\n \"IsWaxing\": true\n },\n \"Zodiac\": {\n \"Name\": \"Virgo\",\n \"NameLocalized\": \"Дева\",\n \"Emoji\": \"♍\"\n },\n \"MoonPosition\": {\n \"Time\": \"2025-01-01 01:01\",\n \"AzimuthDegrees\": 356.08557,\n \"AltitudeDegrees\": -65.49632,\n \"Direction\": \"N\",\n \"DistanceKm\": 382316.55173\n }\n },\n \"EndDay\": {\n \"MoonDays\": 1.85568,\n \"Illumination\": 2.79491,\n \"Phase\": {\n \"Name\": \"New Moon\",\n \"NameLocalized\": \"Новолуние\",\n \"Emoji\": \"🌑\",\n \"IsWaxing\": true\n },\n \"Zodiac\": {\n \"Name\": \"Virgo\",\n \"NameLocalized\": \"Дева\",\n \"Emoji\": \"♍\"\n },\n \"MoonPosition\": {\n \"Time\": \"2025-01-02 00:00\",\n \"AzimuthDegrees\": 309.21002,\n \"AltitudeDegrees\": -54.25535,\n \"Direction\": \"NW\",\n \"DistanceKm\": 379194.7976\n }\n },\n \"MoonDaysDetailed\": {\n \"Count\": 2,\n \"Day\": [\n {\n \"Begin\": \"2024-12-31 09:18\",\n \"IsBeginExists\": true,\n \"End\": \"2025-01-01 09:55\",\n \"IsEndExists\": true\n },\n {\n \"Begin\": \"2025-01-01 09:55\",\n \"IsBeginExists\": true,\n \"End\": \"2025-01-02 10:21\",\n \"IsEndExists\": true\n }\n ]\n },\n \"ZodiacDetailed\": {\n \"Count\": 1,\n \"Zodiac\": [\n {\n \"Name\": \"Virgo\",\n \"NameLocalized\": \"Дева\",\n \"Emoji\": \"♍\",\n \"Begin\": \"2024-12-31 03:27\",\n \"End\": \"2025-01-02 15:27\"\n }\n ]\n },\n \"MoonRiseAndSet\": {\n \"IsMoonRise\": true,\n \"IsMoonSet\": true,\n \"IsMeridian\": true,\n \"Moonrise\": {\n \"Time\": \"2025-01-01 09:55\",\n \"AzimuthDegrees\": 133.52155,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"SE\",\n \"DistanceKm\": 381054.53085\n },\n \"Moonset\": {\n \"Time\": \"2025-01-01 17:26\",\n \"AzimuthDegrees\": 228.55471,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"SW\",\n \"DistanceKm\": 380040.1844\n },\n \"Meridian\": {\n \"Time\": \"2025-01-01 13:36\",\n \"AzimuthDegrees\": 180,\n \"AltitudeDegrees\": 13.2,\n \"Direction\": \"S\",\n \"DistanceKm\": 380550.46947\n }\n }\n}" }, - "description": "Detailed information:\n\n[https://github.com/prostraction/moon?tab=readme-ov-file#get-v1moonphasedate](https://github.com/prostraction/moon?tab=readme-ov-file#get-v1moonphasedate)\n\nThe method returns 6 objects:\n\n- `BeginDay`, `CurrentState`, `EndDay` objects of the `MoonStat`structure to display the position of the moon at the beginning of the day, the specified time and the end of the day, respectively;\n \n- `MoonDaysDetailed (optional)`, a structure for determining the number of lunar days on a given day;\n \n- `ZodiacDetailed (required)`, a structure for determining which \n zodiac sign the moon is in on a given time interval, when it began and ended. It contains an array for each lunar day that falls on a given Earth day;\n \n- `MoonRiseAndSet (optional)`, a structure for determining the moonrise, moonset and meridian on a given day. Missing if no coords specified. Parts of this struct may be missing." - }, - "response": [ { - "name": "moonPhaseCurrent", + "name": "moonPhaseDate — timestamp timeFormat", "originalRequest": { "method": "GET", "header": [], "url": { - "raw": "{{baseUrl}}/v1/moonPhaseCurrent?utc=UTC+5&lang=ru&precision=5&latitude=51.1655&longitude=71.4272", + "raw": "{{baseUrl}}/v1/moonPhaseDate?utc=UTC+5&lang=ru&precision=5&latitude=51.1655&longitude=71.4272&year=2025&month=01&day=01&hour=01&minute=01&second=01&timeFormat=timestamp", "host": [ "{{baseUrl}}" ], "path": [ "v1", - "moonPhaseCurrent" + "moonPhaseDate" ], "query": [ { @@ -277,6 +340,41 @@ "key": "longitude", "value": "71.4272", "description": "Longitude of viewer's place. Used for moon position calculations: MoonDaysDetailed, MoonRiseAndSet, and MoonPosition object" + }, + { + "key": "year", + "value": "2025", + "description": "Format: YYYY Allowed range: [1, 9999]. Current, if not specified" + }, + { + "key": "month", + "value": "01", + "description": "Format: M or MM. Allowed range: [1, 12]. Current, if not specified" + }, + { + "key": "day", + "value": "01", + "description": "Format: D or DD. Allowed range: [1, 31]. Current, if not specified" + }, + { + "key": "hour", + "value": "01", + "description": "Format: h or hh. Allowed range: [0, 23]. Current, if not specified" + }, + { + "key": "minute", + "value": "01", + "description": "Format: m or mm. Allowed range: [0, 59]. Current, if not specified" + }, + { + "key": "second", + "value": "01", + "description": "Format: s or ss. Allowed range: [0, 59]. Current, if not specified" + }, + { + "key": "timeFormat", + "value": "timestamp", + "description": "Supports: \"ISO\" (default), \"timestamp\" any Go time format directives (without UTC), for example: \"Mon, 02 Jan 2006 15:04:05\"" } ] } @@ -287,49 +385,42 @@ "header": [ { "key": "Server", - "value": "nginx/1.24.0 (Ubuntu)" + "value": "Fiber" }, { "key": "Date", - "value": "Tue, 04 Nov 2025 11:28:16 GMT" + "value": "Sun, 16 Nov 2025 18:20:06 GMT" }, { "key": "Content-Type", "value": "application/json", + "name": "Content-Type", "description": "", "type": "text" }, { "key": "Content-Length", - "value": "2247" - }, - { - "key": "Connection", - "value": "keep-alive" - }, - { - "key": "Keep-Alive", - "value": "timeout=900" + "value": "1826" } ], "cookie": [], - "body": "{\n \"BeginDay\": {\n \"MoonDays\": 13.27363,\n \"Illumination\": 93.79012,\n \"Phase\": {\n \"Name\": \"Waxing Gibbous\",\n \"NameLocalized\": \"Растущая Луна\",\n \"Emoji\": \"🌔\",\n \"IsWaxing\": true\n },\n \"Zodiac\": {\n \"Name\": \"Aquarius\",\n \"NameLocalized\": \"Водолей\",\n \"Emoji\": \"♒\"\n },\n \"MoonPosition\": {\n \"Timestamp\": 1762196400,\n \"TimeISO\": \"2025-11-04T00:00:00+05:00\",\n \"AzimuthDegrees\": 215.21834,\n \"AltitudeDegrees\": 42.12633,\n \"Direction\": \"SW\",\n \"DistanceKm\": 361308.10318\n }\n },\n \"CurrentState\": {\n \"MoonDays\": 13.75159,\n \"Illumination\": 96.27365,\n \"Phase\": {\n \"Name\": \"Full Moon\",\n \"NameLocalized\": \"Полнолуние\",\n \"Emoji\": \"🌕\",\n \"IsWaxing\": true\n },\n \"Zodiac\": {\n \"Name\": \"Aquarius\",\n \"NameLocalized\": \"Водолей\",\n \"Emoji\": \"♒\"\n },\n \"MoonPosition\": {\n \"Timestamp\": 1762237695,\n \"TimeISO\": \"2025-11-04T11:28:15+05:00\",\n \"AzimuthDegrees\": 12.34775,\n \"AltitudeDegrees\": -26.87274,\n \"Direction\": \"NNE\",\n \"DistanceKm\": 359579.90558\n }\n },\n \"EndDay\": {\n \"MoonDays\": 14.27363,\n \"Illumination\": 98.3017,\n \"Phase\": {\n \"Name\": \"Full Moon\",\n \"NameLocalized\": \"Полнолуние\",\n \"Emoji\": \"🌕\",\n \"IsWaxing\": true\n },\n \"Zodiac\": {\n \"Name\": \"Aquarius\",\n \"NameLocalized\": \"Водолей\",\n \"Emoji\": \"♒\"\n },\n \"MoonPosition\": {\n \"Timestamp\": 1762282800,\n \"TimeISO\": \"2025-11-05T00:00:00+05:00\",\n \"AzimuthDegrees\": 200.1139,\n \"AltitudeDegrees\": 52.28516,\n \"Direction\": \"SSW\",\n \"DistanceKm\": 358145.25242\n }\n },\n \"MoonDaysDetailed\": {\n \"Count\": 2,\n \"Day\": [\n {\n \"Begin\": \"2025-11-03T15:31:43+05:00\",\n \"IsBeginExists\": true,\n \"End\": \"2025-11-04T15:47:07+05:00\",\n \"IsEndExists\": true\n },\n {\n \"Begin\": \"2025-11-04T15:47:07+05:00\",\n \"IsBeginExists\": true,\n \"End\": \"2025-11-05T16:06:53+05:00\",\n \"IsEndExists\": true\n }\n ]\n },\n \"ZodiacDetailed\": {\n \"Count\": 1,\n \"Zodiac\": [\n {\n \"Name\": \"Aquarius\",\n \"NameLocalized\": \"Водолей\",\n \"Emoji\": \"♒\",\n \"Begin\": \"2025-11-03T05:25:58+05:00\",\n \"End\": \"2025-11-05T17:25:58+05:00\"\n }\n ]\n },\n \"MoonRiseAndSet\": {\n \"Moonrise\": {\n \"Timestamp\": 1762253227,\n \"TimeISO\": \"2025-11-04T15:47:07+05:00\",\n \"AzimuthDegrees\": 69.12186,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"ENE\",\n \"DistanceKm\": 359030.2047\n },\n \"Moonset\": {\n \"Timestamp\": 1762215573,\n \"TimeISO\": \"2025-11-04T05:19:33+05:00\",\n \"AzimuthDegrees\": 286.14788,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"WNW\",\n \"DistanceKm\": 360458.99957\n },\n \"Meridian\": {\n \"Timestamp\": 1762279703,\n \"TimeISO\": \"2025-11-04T23:08:23+05:00\",\n \"AzimuthDegrees\": 180,\n \"AltitudeDegrees\": 53.4,\n \"Direction\": \"S\",\n \"DistanceKm\": 358227.74281\n },\n \"IsMoonRise\": true,\n \"IsMoonSet\": true,\n \"IsMeridian\": true\n }\n}" + "body": "{\n \"BeginDay\": {\n \"MoonDays\": 0.85568,\n \"Illumination\": 0.35744,\n \"Phase\": {\n \"Name\": \"New Moon\",\n \"NameLocalized\": \"Новолуние\",\n \"Emoji\": \"🌑\",\n \"IsWaxing\": true\n },\n \"Zodiac\": {\n \"Name\": \"Virgo\",\n \"NameLocalized\": \"Дева\",\n \"Emoji\": \"♍\"\n },\n \"MoonPosition\": {\n \"Time\": 1735671600,\n \"AzimuthDegrees\": 326.86255,\n \"AltitudeDegrees\": -62.68617,\n \"Direction\": \"NNW\",\n \"DistanceKm\": 382464.56722\n }\n },\n \"CurrentState\": {\n \"MoonDays\": 0.89806,\n \"Illumination\": 0.4137,\n \"Phase\": {\n \"Name\": \"New Moon\",\n \"NameLocalized\": \"Новолуние\",\n \"Emoji\": \"🌑\",\n \"IsWaxing\": true\n },\n \"Zodiac\": {\n \"Name\": \"Virgo\",\n \"NameLocalized\": \"Дева\",\n \"Emoji\": \"♍\"\n },\n \"MoonPosition\": {\n \"Time\": 1735675261,\n \"AzimuthDegrees\": 356.08557,\n \"AltitudeDegrees\": -65.49632,\n \"Direction\": \"N\",\n \"DistanceKm\": 382316.55173\n }\n },\n \"EndDay\": {\n \"MoonDays\": 1.85568,\n \"Illumination\": 2.79491,\n \"Phase\": {\n \"Name\": \"New Moon\",\n \"NameLocalized\": \"Новолуние\",\n \"Emoji\": \"🌑\",\n \"IsWaxing\": true\n },\n \"Zodiac\": {\n \"Name\": \"Virgo\",\n \"NameLocalized\": \"Дева\",\n \"Emoji\": \"♍\"\n },\n \"MoonPosition\": {\n \"Time\": 1735758000,\n \"AzimuthDegrees\": 309.21002,\n \"AltitudeDegrees\": -54.25535,\n \"Direction\": \"NW\",\n \"DistanceKm\": 379194.7976\n }\n },\n \"MoonDaysDetailed\": {\n \"Count\": 2,\n \"Day\": [\n {\n \"Begin\": 1735618722,\n \"IsBeginExists\": true,\n \"End\": 1735707321,\n \"IsEndExists\": true\n },\n {\n \"Begin\": 1735707321,\n \"IsBeginExists\": true,\n \"End\": 1735795276,\n \"IsEndExists\": true\n }\n ]\n },\n \"ZodiacDetailed\": {\n \"Count\": 1,\n \"Zodiac\": [\n {\n \"Name\": \"Virgo\",\n \"NameLocalized\": \"Дева\",\n \"Emoji\": \"♍\",\n \"Begin\": 1735597669,\n \"End\": 1735813669\n }\n ]\n },\n \"MoonRiseAndSet\": {\n \"IsMoonRise\": true,\n \"IsMoonSet\": true,\n \"IsMeridian\": true,\n \"Moonrise\": {\n \"Time\": 1735707321,\n \"AzimuthDegrees\": 133.52155,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"SE\",\n \"DistanceKm\": 381054.53085\n },\n \"Moonset\": {\n \"Time\": 1735734376,\n \"AzimuthDegrees\": 228.55471,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"SW\",\n \"DistanceKm\": 380040.1844\n },\n \"Meridian\": {\n \"Time\": 1735720605,\n \"AzimuthDegrees\": 180,\n \"AltitudeDegrees\": 13.2,\n \"Direction\": \"S\",\n \"DistanceKm\": 380550.46947\n }\n }\n}" } ] }, { - "name": "Get moon phase by timestamp", + "name": "Get moon phase by current date", "request": { "method": "GET", "header": [], "url": { - "raw": "{{baseUrl}}/v1/moonPhaseTimestamp?utc=UTC+5&lang=ru&precision=5&latitude=51.1655&longitude=71.4272×tamp=1758045697", + "raw": "{{baseUrl}}/v1/moonPhaseCurrent?utc=UTC+5&lang=ru&precision=5&latitude=51.1655&longitude=71.4272&timeFormat=2006-01-02 15:04", "host": [ "{{baseUrl}}" ], "path": [ "v1", - "moonPhaseTimestamp" + "moonPhaseCurrent" ], "query": [ { @@ -358,9 +449,9 @@ "description": "Longitude of viewer's place. Used for moon position calculations: MoonDaysDetailed, MoonRiseAndSet, and MoonPosition object" }, { - "key": "timestamp", - "value": "1758045697", - "description": "Timestamp for calculations" + "key": "timeFormat", + "value": "2006-01-02 15:04", + "description": "Supports: \"ISO\" (default), \"timestamp\" any Go time format directives (without UTC), for example: \"Mon, 02 Jan 2006 15:04:05\"" } ] }, @@ -368,18 +459,18 @@ }, "response": [ { - "name": "moonPhaseTimestamp", + "name": "moonPhaseCurrent", "originalRequest": { "method": "GET", "header": [], "url": { - "raw": "{{baseUrl}}/v1/moonPhaseTimestamp?utc=UTC+5&lang=ru&precision=5&latitude=51.1655&longitude=71.4272×tamp=1758045697", + "raw": "{{baseUrl}}/v1/moonPhaseCurrent?utc=UTC+5&lang=ru&precision=5&latitude=51.1655&longitude=71.4272", "host": [ "{{baseUrl}}" ], "path": [ "v1", - "moonPhaseTimestamp" + "moonPhaseCurrent" ], "query": [ { @@ -406,11 +497,6 @@ "key": "longitude", "value": "71.4272", "description": "Longitude of viewer's place. Used for moon position calculations: MoonDaysDetailed, MoonRiseAndSet, and MoonPosition object" - }, - { - "key": "timestamp", - "value": "1758045697", - "description": "Timestamp for calculations" } ] } @@ -425,18 +511,17 @@ }, { "key": "Date", - "value": "Tue, 04 Nov 2025 11:30:48 GMT" + "value": "Tue, 04 Nov 2025 11:28:16 GMT" }, { "key": "Content-Type", "value": "application/json", - "name": "Content-Type", "description": "", "type": "text" }, { "key": "Content-Length", - "value": "2239" + "value": "2247" }, { "key": "Connection", @@ -448,69 +533,52 @@ } ], "cookie": [], - "body": "{\n \"BeginDay\": {\n \"MoonDays\": 23.53674,\n \"Illumination\": 38.2726,\n \"Phase\": {\n \"Name\": \"Waning Crescent\",\n \"NameLocalized\": \"Убывающий серп\",\n \"Emoji\": \"🌘\",\n \"IsWaxing\": false\n },\n \"Zodiac\": {\n \"Name\": \"Gemini\",\n \"NameLocalized\": \"Близнецы\",\n \"Emoji\": \"♊\"\n },\n \"MoonPosition\": {\n \"Timestamp\": 1757962800,\n \"TimeISO\": \"2025-09-16T00:00:00+05:00\",\n \"AzimuthDegrees\": 57.08873,\n \"AltitudeDegrees\": 8.79646,\n \"Direction\": \"ENE\",\n \"DistanceKm\": 376559.88437\n }\n },\n \"CurrentState\": {\n \"MoonDays\": 24.28786,\n \"Illumination\": 30.38659,\n \"Phase\": {\n \"Name\": \"Waning Crescent\",\n \"NameLocalized\": \"Убывающий серп\",\n \"Emoji\": \"🌘\",\n \"IsWaxing\": false\n },\n \"Zodiac\": {\n \"Name\": \"Gemini\",\n \"NameLocalized\": \"Близнецы\",\n \"Emoji\": \"♊\"\n },\n \"MoonPosition\": {\n \"Timestamp\": 1758027697,\n \"TimeISO\": \"2025-09-16T18:01:37+05:00\",\n \"AzimuthDegrees\": 332.40261,\n \"AltitudeDegrees\": -8.94892,\n \"Direction\": \"NNW\",\n \"DistanceKm\": 379152.9693\n }\n },\n \"EndDay\": {\n \"MoonDays\": 24.53674,\n \"Illumination\": 27.90729,\n \"Phase\": {\n \"Name\": \"Waning Crescent\",\n \"NameLocalized\": \"Убывающий серп\",\n \"Emoji\": \"🌘\",\n \"IsWaxing\": false\n },\n \"Zodiac\": {\n \"Name\": \"Gemini\",\n \"NameLocalized\": \"Близнецы\",\n \"Emoji\": \"♊\"\n },\n \"MoonPosition\": {\n \"Timestamp\": 1758049200,\n \"TimeISO\": \"2025-09-17T00:00:00+05:00\",\n \"AzimuthDegrees\": 48.0345,\n \"AltitudeDegrees\": -0.14735,\n \"Direction\": \"NE\",\n \"DistanceKm\": 380020.57994\n }\n },\n \"MoonDaysDetailed\": {\n \"Count\": 2,\n \"Day\": [\n {\n \"Begin\": \"2025-09-15T22:37:45+05:00\",\n \"IsBeginExists\": true,\n \"End\": \"2025-09-16T23:56:10+05:00\",\n \"IsEndExists\": true\n },\n {\n \"Begin\": \"2025-09-16T23:56:10+05:00\",\n \"IsBeginExists\": true,\n \"IsEndExists\": false\n }\n ]\n },\n \"ZodiacDetailed\": {\n \"Count\": 1,\n \"Zodiac\": [\n {\n \"Name\": \"Gemini\",\n \"NameLocalized\": \"Близнецы\",\n \"Emoji\": \"♊\",\n \"Begin\": \"2025-09-14T23:07:06+05:00\",\n \"End\": \"2025-09-17T11:07:06+05:00\"\n }\n ]\n },\n \"MoonRiseAndSet\": {\n \"Moonrise\": {\n \"Timestamp\": 1758048970,\n \"TimeISO\": \"2025-09-16T23:56:10+05:00\",\n \"AzimuthDegrees\": 47.31764,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"NE\",\n \"DistanceKm\": 380011.3104\n },\n \"Moonset\": {\n \"Timestamp\": 1758022192,\n \"TimeISO\": \"2025-09-16T16:29:52+05:00\",\n \"AzimuthDegrees\": 314.4689,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"NW\",\n \"DistanceKm\": 378931.34559\n },\n \"Meridian\": {\n \"Timestamp\": 1757990436,\n \"TimeISO\": \"2025-09-16T07:40:36+05:00\",\n \"AzimuthDegrees\": 180,\n \"AltitudeDegrees\": 65.7,\n \"Direction\": \"S\",\n \"DistanceKm\": 377658.15629\n },\n \"IsMoonRise\": true,\n \"IsMoonSet\": true,\n \"IsMeridian\": true\n }\n}" - } - ] - } - ] - }, - { - "name": "Moon Phase — Core information for year", - "item": [ - { - "name": "Get moon phases table by specified year", - "request": { - "method": "GET", - "header": [], - "url": { - "raw": "{{baseUrl}}/v1/moonTableYear?utc=5&year=2025", - "host": [ - "{{baseUrl}}" - ], - "path": [ - "v1", - "moonTableYear" - ], - "query": [ - { - "key": "utc", - "value": "5", - "description": "Timezone. Example: \"UTC+5\", \"5\", \"-10:30\"" - }, - { - "key": "year", - "value": "2025", - "description": "Year for request: YYYY" - } - ] + "body": "{\n \"BeginDay\": {\n \"MoonDays\": 25.27363,\n \"Illumination\": 19.40433,\n \"Phase\": {\n \"Name\": \"Waning Crescent\",\n \"NameLocalized\": \"Убывающий серп\",\n \"Emoji\": \"🌘\",\n \"IsWaxing\": false\n },\n \"Zodiac\": {\n \"Name\": \"Cancer\",\n \"NameLocalized\": \"Рак\",\n \"Emoji\": \"♋\"\n },\n \"MoonPosition\": {\n \"Time\": \"2025-11-16T00:00:00+05:00\",\n \"AzimuthDegrees\": 56.78112,\n \"AltitudeDegrees\": -28.52163,\n \"Direction\": \"ENE\",\n \"DistanceKm\": 400130.90444\n }\n },\n \"CurrentState\": {\n \"MoonDays\": 26.24569,\n \"Illumination\": 12.55125,\n \"Phase\": {\n \"Name\": \"Waning Crescent\",\n \"NameLocalized\": \"Убывающий серп\",\n \"Emoji\": \"🌘\",\n \"IsWaxing\": false\n },\n \"Zodiac\": {\n \"Name\": \"Cancer\",\n \"NameLocalized\": \"Рак\",\n \"Emoji\": \"♋\"\n },\n \"MoonPosition\": {\n \"Time\": \"2025-11-16T23:19:46+05:00\",\n \"AzimuthDegrees\": 38.89192,\n \"AltitudeDegrees\": -42.30857,\n \"Direction\": \"NE\",\n \"DistanceKm\": 402829.6361\n }\n },\n \"EndDay\": {\n \"MoonDays\": 26.27363,\n \"Illumination\": 12.37382,\n \"Phase\": {\n \"Name\": \"Waning Crescent\",\n \"NameLocalized\": \"Убывающий серп\",\n \"Emoji\": \"🌘\",\n \"IsWaxing\": false\n },\n \"Zodiac\": {\n \"Name\": \"Cancer\",\n \"NameLocalized\": \"Рак\",\n \"Emoji\": \"♋\"\n },\n \"MoonPosition\": {\n \"Time\": \"2025-11-17T00:00:00+05:00\",\n \"AzimuthDegrees\": 50.22016,\n \"AltitudeDegrees\": -38.1823,\n \"Direction\": \"NE\",\n \"DistanceKm\": 402895.89872\n }\n },\n \"MoonDaysDetailed\": {\n \"Count\": 2,\n \"Day\": [\n {\n \"Begin\": \"2025-11-15T02:05:18+05:00\",\n \"IsBeginExists\": true,\n \"End\": \"2025-11-16T03:16:31+05:00\",\n \"IsEndExists\": true\n },\n {\n \"Begin\": \"2025-11-16T03:16:31+05:00\",\n \"IsBeginExists\": true,\n \"End\": \"2025-11-17T04:27:24+05:00\",\n \"IsEndExists\": true\n }\n ]\n },\n \"ZodiacDetailed\": {\n \"Count\": 1,\n \"Zodiac\": [\n {\n \"Name\": \"Cancer\",\n \"NameLocalized\": \"Рак\",\n \"Emoji\": \"♋\",\n \"Begin\": \"2025-11-15T17:25:58+05:00\",\n \"End\": \"2025-11-18T05:25:58+05:00\"\n }\n ]\n },\n \"MoonRiseAndSet\": {\n \"IsMoonRise\": true,\n \"IsMoonSet\": true,\n \"IsMeridian\": true,\n \"Moonrise\": {\n \"Time\": \"2025-11-16T03:16:31+05:00\",\n \"AzimuthDegrees\": 97.01341,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"E\",\n \"DistanceKm\": 400556.57352\n },\n \"Moonset\": {\n \"Time\": \"2025-11-16T14:35:54+05:00\",\n \"AzimuthDegrees\": 258.70682,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"WSW\",\n \"DistanceKm\": 401909.79218\n },\n \"Meridian\": {\n \"Time\": \"2025-11-16T09:03:07+05:00\",\n \"AzimuthDegrees\": 180,\n \"AltitudeDegrees\": 32.6,\n \"Direction\": \"S\",\n \"DistanceKm\": 401269.77889\n }\n }\n}" }, - "description": "Detailed information:\n\n[https://github.com/prostraction/moon?tab=readme-ov-file#get-v1moontableyear](https://github.com/prostraction/moon?tab=readme-ov-file#get-v1moontableyear)\n\nThe method returns the moon phases for the given year. The response contains an array for each month, each element of which contains the time of the new moon, first quarter, full moon, last quarter." - }, - "response": [ { - "name": "moonTableYear", + "name": "moonPhaseCurrent — custom timeFormat", "originalRequest": { "method": "GET", "header": [], "url": { - "raw": "{{baseUrl}}/v1/moonTableYear?utc=5&year=2025", + "raw": "{{baseUrl}}/v1/moonPhaseCurrent?utc=UTC+5&lang=ru&precision=5&latitude=51.1655&longitude=71.4272&timeFormat=2006-01-02 15:04", "host": [ "{{baseUrl}}" ], "path": [ "v1", - "moonTableYear" + "moonPhaseCurrent" ], "query": [ { "key": "utc", + "value": "UTC+5", + "description": "UTC in format UTC+7, UTC+09:30, -3" + }, + { + "key": "lang", + "value": "ru", + "description": "Values available: (\"en\", \"es\", \"fr\", \"de\", \"ru\", \"jp\")" + }, + { + "key": "precision", "value": "5", - "description": "Timezone. Example: \"UTC+5\", \"5\", \"-10:30\"" + "description": "How many digits after . will be in output. Allowed range: [1, 20]" }, { - "key": "year", - "value": "2025", - "description": "Year for request: YYYY" + "key": "latitude", + "value": "51.1655", + "description": "Latitude of viewer's place. Used for moon position calculations: MoonDaysDetailed, MoonRiseAndSet, and MoonPosition object" + }, + { + "key": "longitude", + "value": "71.4272", + "description": "Longitude of viewer's place. Used for moon position calculations: MoonDaysDetailed, MoonRiseAndSet, and MoonPosition object" + }, + { + "key": "timeFormat", + "value": "2006-01-02 15:04", + "description": "Supports: \"ISO\" (default), \"timestamp\" any Go time format directives (without UTC), for example: \"Mon, 02 Jan 2006 15:04:05\"" } ] } @@ -521,39 +589,1990 @@ "header": [ { "key": "Server", - "value": "nginx/1.24.0 (Ubuntu)" + "value": "Fiber" }, { "key": "Date", - "value": "Tue, 04 Nov 2025 11:31:11 GMT" + "value": "Sun, 16 Nov 2025 17:54:42 GMT" }, { "key": "Content-Type", "value": "application/json", - "name": "Content-Type", "description": "", "type": "text" }, { "key": "Content-Length", - "value": "2133" - }, - { - "key": "Connection", - "value": "keep-alive" - }, + "value": "1889" + } + ], + "cookie": [], + "body": "{\n \"BeginDay\": {\n \"MoonDays\": 25.27363,\n \"Illumination\": 19.40433,\n \"Phase\": {\n \"Name\": \"Waning Crescent\",\n \"NameLocalized\": \"Убывающий серп\",\n \"Emoji\": \"🌘\",\n \"IsWaxing\": false\n },\n \"Zodiac\": {\n \"Name\": \"Cancer\",\n \"NameLocalized\": \"Рак\",\n \"Emoji\": \"♋\"\n },\n \"MoonPosition\": {\n \"Time\": \"2025-11-16 00:00\",\n \"AzimuthDegrees\": 56.78112,\n \"AltitudeDegrees\": -28.52163,\n \"Direction\": \"ENE\",\n \"DistanceKm\": 400130.90444\n }\n },\n \"CurrentState\": {\n \"MoonDays\": 26.24558,\n \"Illumination\": 12.55199,\n \"Phase\": {\n \"Name\": \"Waning Crescent\",\n \"NameLocalized\": \"Убывающий серп\",\n \"Emoji\": \"🌘\",\n \"IsWaxing\": false\n },\n \"Zodiac\": {\n \"Name\": \"Cancer\",\n \"NameLocalized\": \"Рак\",\n \"Emoji\": \"♋\"\n },\n \"MoonPosition\": {\n \"Time\": \"2025-11-16 23:19\",\n \"AzimuthDegrees\": 38.84242,\n \"AltitudeDegrees\": -42.32378,\n \"Direction\": \"NE\",\n \"DistanceKm\": 402829.36032\n }\n },\n \"EndDay\": {\n \"MoonDays\": 26.27363,\n \"Illumination\": 12.37382,\n \"Phase\": {\n \"Name\": \"Waning Crescent\",\n \"NameLocalized\": \"Убывающий серп\",\n \"Emoji\": \"🌘\",\n \"IsWaxing\": false\n },\n \"Zodiac\": {\n \"Name\": \"Cancer\",\n \"NameLocalized\": \"Рак\",\n \"Emoji\": \"♋\"\n },\n \"MoonPosition\": {\n \"Time\": \"2025-11-17 00:00\",\n \"AzimuthDegrees\": 50.22016,\n \"AltitudeDegrees\": -38.1823,\n \"Direction\": \"NE\",\n \"DistanceKm\": 402895.89872\n }\n },\n \"MoonDaysDetailed\": {\n \"Count\": 2,\n \"Day\": [\n {\n \"Begin\": \"2025-11-15 02:05\",\n \"IsBeginExists\": true,\n \"End\": \"2025-11-16 03:16\",\n \"IsEndExists\": true\n },\n {\n \"Begin\": \"2025-11-16 03:16\",\n \"IsBeginExists\": true,\n \"End\": \"2025-11-17 04:27\",\n \"IsEndExists\": true\n }\n ]\n },\n \"ZodiacDetailed\": {\n \"Count\": 1,\n \"Zodiac\": [\n {\n \"Name\": \"Cancer\",\n \"NameLocalized\": \"Рак\",\n \"Emoji\": \"♋\",\n \"Begin\": \"2025-11-15 17:25\",\n \"End\": \"2025-11-18 05:25\"\n }\n ]\n },\n \"MoonRiseAndSet\": {\n \"IsMoonRise\": true,\n \"IsMoonSet\": true,\n \"IsMeridian\": true,\n \"Moonrise\": {\n \"Time\": \"2025-11-16 03:16\",\n \"AzimuthDegrees\": 97.01341,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"E\",\n \"DistanceKm\": 400556.57352\n },\n \"Moonset\": {\n \"Time\": \"2025-11-16 14:35\",\n \"AzimuthDegrees\": 258.70682,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"WSW\",\n \"DistanceKm\": 401909.79218\n },\n \"Meridian\": {\n \"Time\": \"2025-11-16 09:03\",\n \"AzimuthDegrees\": 180,\n \"AltitudeDegrees\": 32.6,\n \"Direction\": \"S\",\n \"DistanceKm\": 401269.77889\n }\n }\n}" + }, + { + "name": "moonPhaseCurrent — timestamp timeFormat", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/v1/moonPhaseCurrent?utc=UTC+5&lang=ru&precision=5&latitude=51.1655&longitude=71.4272&timeFormat=timestamp", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "v1", + "moonPhaseCurrent" + ], + "query": [ + { + "key": "utc", + "value": "UTC+5", + "description": "UTC in format UTC+7, UTC+09:30, -3" + }, + { + "key": "lang", + "value": "ru", + "description": "Values available: (\"en\", \"es\", \"fr\", \"de\", \"ru\", \"jp\")" + }, + { + "key": "precision", + "value": "5", + "description": "How many digits after . will be in output. Allowed range: [1, 20]" + }, + { + "key": "latitude", + "value": "51.1655", + "description": "Latitude of viewer's place. Used for moon position calculations: MoonDaysDetailed, MoonRiseAndSet, and MoonPosition object" + }, + { + "key": "longitude", + "value": "71.4272", + "description": "Longitude of viewer's place. Used for moon position calculations: MoonDaysDetailed, MoonRiseAndSet, and MoonPosition object" + }, + { + "key": "timeFormat", + "value": "timestamp", + "description": "Supports: \"ISO\" (default), \"timestamp\" any Go time format directives (without UTC), for example: \"Mon, 02 Jan 2006 15:04:05\"" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Server", + "value": "Fiber" + }, + { + "key": "Date", + "value": "Sun, 16 Nov 2025 17:59:09 GMT" + }, + { + "key": "Content-Type", + "value": "application/json", + "name": "Content-Type", + "description": "", + "type": "text" + }, + { + "key": "Content-Length", + "value": "1840" + } + ], + "cookie": [], + "body": "{\n \"BeginDay\": {\n \"MoonDays\": 25.27363,\n \"Illumination\": 19.40433,\n \"Phase\": {\n \"Name\": \"Waning Crescent\",\n \"NameLocalized\": \"Убывающий серп\",\n \"Emoji\": \"🌘\",\n \"IsWaxing\": false\n },\n \"Zodiac\": {\n \"Name\": \"Cancer\",\n \"NameLocalized\": \"Рак\",\n \"Emoji\": \"♋\"\n },\n \"MoonPosition\": {\n \"Time\": 1763233200,\n \"AzimuthDegrees\": 56.78112,\n \"AltitudeDegrees\": -28.52163,\n \"Direction\": \"ENE\",\n \"DistanceKm\": 400130.90444\n }\n },\n \"CurrentState\": {\n \"MoonDays\": 26.24535,\n \"Illumination\": 12.55346,\n \"Phase\": {\n \"Name\": \"Waning Crescent\",\n \"NameLocalized\": \"Убывающий серп\",\n \"Emoji\": \"🌘\",\n \"IsWaxing\": false\n },\n \"Zodiac\": {\n \"Name\": \"Cancer\",\n \"NameLocalized\": \"Рак\",\n \"Emoji\": \"♋\"\n },\n \"MoonPosition\": {\n \"Time\": 1763317156,\n \"AzimuthDegrees\": 38.74335,\n \"AltitudeDegrees\": -42.35414,\n \"Direction\": \"NE\",\n \"DistanceKm\": 402828.80872\n }\n },\n \"EndDay\": {\n \"MoonDays\": 26.27363,\n \"Illumination\": 12.37382,\n \"Phase\": {\n \"Name\": \"Waning Crescent\",\n \"NameLocalized\": \"Убывающий серп\",\n \"Emoji\": \"🌘\",\n \"IsWaxing\": false\n },\n \"Zodiac\": {\n \"Name\": \"Cancer\",\n \"NameLocalized\": \"Рак\",\n \"Emoji\": \"♋\"\n },\n \"MoonPosition\": {\n \"Time\": 1763319600,\n \"AzimuthDegrees\": 50.22016,\n \"AltitudeDegrees\": -38.1823,\n \"Direction\": \"NE\",\n \"DistanceKm\": 402895.89872\n }\n },\n \"MoonDaysDetailed\": {\n \"Count\": 2,\n \"Day\": [\n {\n \"Begin\": 1763154318,\n \"IsBeginExists\": true,\n \"End\": 1763244991,\n \"IsEndExists\": true\n },\n {\n \"Begin\": 1763244991,\n \"IsBeginExists\": true,\n \"End\": 1763335644,\n \"IsEndExists\": true\n }\n ]\n },\n \"ZodiacDetailed\": {\n \"Count\": 1,\n \"Zodiac\": [\n {\n \"Name\": \"Cancer\",\n \"NameLocalized\": \"Рак\",\n \"Emoji\": \"♋\",\n \"Begin\": 1763209558,\n \"End\": 1763425558\n }\n ]\n },\n \"MoonRiseAndSet\": {\n \"IsMoonRise\": true,\n \"IsMoonSet\": true,\n \"IsMeridian\": true,\n \"Moonrise\": {\n \"Time\": 1763244991,\n \"AzimuthDegrees\": 97.01341,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"E\",\n \"DistanceKm\": 400556.57352\n },\n \"Moonset\": {\n \"Time\": 1763285754,\n \"AzimuthDegrees\": 258.70682,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"WSW\",\n \"DistanceKm\": 401909.79218\n },\n \"Meridian\": {\n \"Time\": 1763265787,\n \"AzimuthDegrees\": 180,\n \"AltitudeDegrees\": 32.6,\n \"Direction\": \"S\",\n \"DistanceKm\": 401269.77889\n }\n }\n}" + } + ] + }, + { + "name": "Get moon phase by timestamp", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/v1/moonPhaseTimestamp?utc=UTC+5&lang=ru&precision=5&latitude=51.1655&longitude=71.4272×tamp=1758045697&timeFormat=2006-01-02 15:04", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "v1", + "moonPhaseTimestamp" + ], + "query": [ + { + "key": "utc", + "value": "UTC+5", + "description": "UTC in format UTC+7, UTC+09:30, -3" + }, + { + "key": "lang", + "value": "ru", + "description": "Values available: (\"en\", \"es\", \"fr\", \"de\", \"ru\", \"jp\")" + }, + { + "key": "precision", + "value": "5", + "description": "How many digits after . will be in output. Allowed range: [1, 20]" + }, + { + "key": "latitude", + "value": "51.1655", + "description": "Latitude of viewer's place. Used for moon position calculations: MoonDaysDetailed, MoonRiseAndSet, and MoonPosition object" + }, + { + "key": "longitude", + "value": "71.4272", + "description": "Longitude of viewer's place. Used for moon position calculations: MoonDaysDetailed, MoonRiseAndSet, and MoonPosition object" + }, + { + "key": "timestamp", + "value": "1758045697", + "description": "Timestamp for calculations. Current, if not specified" + }, + { + "key": "timeFormat", + "value": "2006-01-02 15:04", + "description": "Supports: \"ISO\" (default), \"timestamp\" any Go time format directives (without UTC), for example: \"Mon, 02 Jan 2006 15:04:05\"" + } + ] + }, + "description": "Detailed information:\n\n[https://github.com/prostraction/moon?tab=readme-ov-file#get-v1moonphasedate](https://github.com/prostraction/moon?tab=readme-ov-file#get-v1moonphasedate)\n\nThe method returns 6 objects:\n\n- `BeginDay`, `CurrentState`, `EndDay` objects of the `MoonStat`structure to display the position of the moon at the beginning of the day, the specified time and the end of the day, respectively;\n \n- `MoonDaysDetailed (optional)`, a structure for determining the number of lunar days on a given day;\n \n- `ZodiacDetailed (required)`, a structure for determining which \n zodiac sign the moon is in on a given time interval, when it began and ended. It contains an array for each lunar day that falls on a given Earth day;\n \n- `MoonRiseAndSet (optional)`, a structure for determining the moonrise, moonset and meridian on a given day. Missing if no coords specified. Parts of this struct may be missing." + }, + "response": [ + { + "name": "moonPhaseTimestamp", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/v1/moonPhaseTimestamp?utc=UTC+5&lang=ru&precision=5&latitude=51.1655&longitude=71.4272×tamp=1758045697", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "v1", + "moonPhaseTimestamp" + ], + "query": [ + { + "key": "utc", + "value": "UTC+5", + "description": "UTC in format UTC+7, UTC+09:30, -3" + }, + { + "key": "lang", + "value": "ru", + "description": "Values available: (\"en\", \"es\", \"fr\", \"de\", \"ru\", \"jp\")" + }, + { + "key": "precision", + "value": "5", + "description": "How many digits after . will be in output. Allowed range: [1, 20]" + }, + { + "key": "latitude", + "value": "51.1655", + "description": "Latitude of viewer's place. Used for moon position calculations: MoonDaysDetailed, MoonRiseAndSet, and MoonPosition object" + }, + { + "key": "longitude", + "value": "71.4272", + "description": "Longitude of viewer's place. Used for moon position calculations: MoonDaysDetailed, MoonRiseAndSet, and MoonPosition object" + }, + { + "key": "timestamp", + "value": "1758045697", + "description": "Timestamp for calculations. Current, if not specified" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Server", + "value": "nginx/1.24.0 (Ubuntu)" + }, + { + "key": "Date", + "value": "Tue, 04 Nov 2025 11:30:48 GMT" + }, + { + "key": "Content-Type", + "value": "application/json", + "description": "", + "type": "text" + }, + { + "key": "Content-Length", + "value": "2239" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Keep-Alive", + "value": "timeout=900" + } + ], + "cookie": [], + "body": "{\n \"BeginDay\": {\n \"MoonDays\": 23.53674,\n \"Illumination\": 38.2726,\n \"Phase\": {\n \"Name\": \"Waning Crescent\",\n \"NameLocalized\": \"Убывающий серп\",\n \"Emoji\": \"🌘\",\n \"IsWaxing\": false\n },\n \"Zodiac\": {\n \"Name\": \"Gemini\",\n \"NameLocalized\": \"Близнецы\",\n \"Emoji\": \"♊\"\n },\n \"MoonPosition\": {\n \"Time\": \"2025-09-16T00:00:00+05:00\",\n \"AzimuthDegrees\": 57.08873,\n \"AltitudeDegrees\": 8.79646,\n \"Direction\": \"ENE\",\n \"DistanceKm\": 376559.88437\n }\n },\n \"CurrentState\": {\n \"MoonDays\": 24.28786,\n \"Illumination\": 30.38659,\n \"Phase\": {\n \"Name\": \"Waning Crescent\",\n \"NameLocalized\": \"Убывающий серп\",\n \"Emoji\": \"🌘\",\n \"IsWaxing\": false\n },\n \"Zodiac\": {\n \"Name\": \"Gemini\",\n \"NameLocalized\": \"Близнецы\",\n \"Emoji\": \"♊\"\n },\n \"MoonPosition\": {\n \"Time\": \"2025-09-16T18:01:37+05:00\",\n \"AzimuthDegrees\": 332.40261,\n \"AltitudeDegrees\": -8.94892,\n \"Direction\": \"NNW\",\n \"DistanceKm\": 379152.9693\n }\n },\n \"EndDay\": {\n \"MoonDays\": 24.53674,\n \"Illumination\": 27.90729,\n \"Phase\": {\n \"Name\": \"Waning Crescent\",\n \"NameLocalized\": \"Убывающий серп\",\n \"Emoji\": \"🌘\",\n \"IsWaxing\": false\n },\n \"Zodiac\": {\n \"Name\": \"Gemini\",\n \"NameLocalized\": \"Близнецы\",\n \"Emoji\": \"♊\"\n },\n \"MoonPosition\": {\n \"Time\": \"2025-09-17T00:00:00+05:00\",\n \"AzimuthDegrees\": 48.0345,\n \"AltitudeDegrees\": -0.14735,\n \"Direction\": \"NE\",\n \"DistanceKm\": 380020.57994\n }\n },\n \"MoonDaysDetailed\": {\n \"Count\": 2,\n \"Day\": [\n {\n \"Begin\": \"2025-09-15T22:37:45+05:00\",\n \"IsBeginExists\": true,\n \"End\": \"2025-09-16T23:56:10+05:00\",\n \"IsEndExists\": true\n },\n {\n \"Begin\": \"2025-09-16T23:56:10+05:00\",\n \"IsBeginExists\": true,\n \"IsEndExists\": false\n }\n ]\n },\n \"ZodiacDetailed\": {\n \"Count\": 1,\n \"Zodiac\": [\n {\n \"Name\": \"Gemini\",\n \"NameLocalized\": \"Близнецы\",\n \"Emoji\": \"♊\",\n \"Begin\": \"2025-09-14T23:07:06+05:00\",\n \"End\": \"2025-09-17T11:07:06+05:00\"\n }\n ]\n },\n \"MoonRiseAndSet\": {\n \"IsMoonRise\": true,\n \"IsMoonSet\": true,\n \"IsMeridian\": true,\n \"Moonrise\": {\n \"Time\": \"2025-09-16T23:56:10+05:00\",\n \"AzimuthDegrees\": 47.31764,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"NE\",\n \"DistanceKm\": 380011.3104\n },\n \"Moonset\": {\n \"Time\": \"2025-09-16T16:29:52+05:00\",\n \"AzimuthDegrees\": 314.4689,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"NW\",\n \"DistanceKm\": 378931.34559\n },\n \"Meridian\": {\n \"Time\": \"2025-09-16T07:40:36+05:00\",\n \"AzimuthDegrees\": 180,\n \"AltitudeDegrees\": 65.7,\n \"Direction\": \"S\",\n \"DistanceKm\": 377658.15629\n }\n }\n}" + }, + { + "name": "moonPhaseTimestamp — custom timeFormat", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/v1/moonPhaseTimestamp?utc=UTC+5&lang=ru&precision=5&latitude=51.1655&longitude=71.4272×tamp=1758045697&timeFormat=2006-01-02 15:04", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "v1", + "moonPhaseTimestamp" + ], + "query": [ + { + "key": "utc", + "value": "UTC+5", + "description": "UTC in format UTC+7, UTC+09:30, -3" + }, + { + "key": "lang", + "value": "ru", + "description": "Values available: (\"en\", \"es\", \"fr\", \"de\", \"ru\", \"jp\")" + }, + { + "key": "precision", + "value": "5", + "description": "How many digits after . will be in output. Allowed range: [1, 20]" + }, + { + "key": "latitude", + "value": "51.1655", + "description": "Latitude of viewer's place. Used for moon position calculations: MoonDaysDetailed, MoonRiseAndSet, and MoonPosition object" + }, + { + "key": "longitude", + "value": "71.4272", + "description": "Longitude of viewer's place. Used for moon position calculations: MoonDaysDetailed, MoonRiseAndSet, and MoonPosition object" + }, + { + "key": "timestamp", + "value": "1758045697", + "description": "Timestamp for calculations. Current, if not specified" + }, + { + "key": "timeFormat", + "value": "2006-01-02 15:04", + "description": "Supports: \"ISO\" (default), \"timestamp\" any Go time format directives (without UTC), for example: \"Mon, 02 Jan 2006 15:04:05\"" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "Text", + "header": [ + { + "key": "Server", + "value": "Fiber" + }, + { + "key": "Date", + "value": "Sun, 16 Nov 2025 18:23:44 GMT" + }, + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Content-Length", + "value": "1983" + } + ], + "cookie": [], + "body": "{\n \"BeginDay\": {\n \"MoonDays\": 23.53674,\n \"Illumination\": 38.2726,\n \"Phase\": {\n \"Name\": \"Waning Crescent\",\n \"NameLocalized\": \"Убывающий серп\",\n \"Emoji\": \"🌘\",\n \"IsWaxing\": false\n },\n \"Zodiac\": {\n \"Name\": \"Gemini\",\n \"NameLocalized\": \"Близнецы\",\n \"Emoji\": \"♊\"\n },\n \"MoonPosition\": {\n \"Time\": \"2025-09-16 00:00\",\n \"AzimuthDegrees\": 57.08873,\n \"AltitudeDegrees\": 8.79646,\n \"Direction\": \"ENE\",\n \"DistanceKm\": 376559.88437\n }\n },\n \"CurrentState\": {\n \"MoonDays\": 24.49619,\n \"Illumination\": 28.30607,\n \"Phase\": {\n \"Name\": \"Waning Crescent\",\n \"NameLocalized\": \"Убывающий серп\",\n \"Emoji\": \"🌘\",\n \"IsWaxing\": false\n },\n \"Zodiac\": {\n \"Name\": \"Gemini\",\n \"NameLocalized\": \"Близнецы\",\n \"Emoji\": \"♊\"\n },\n \"MoonPosition\": {\n \"Time\": \"2025-09-16 23:01\",\n \"AzimuthDegrees\": 36.77206,\n \"AltitudeDegrees\": -5.96783,\n \"Direction\": \"NE\",\n \"DistanceKm\": 379879.05898\n }\n },\n \"EndDay\": {\n \"MoonDays\": 24.53674,\n \"Illumination\": 27.90729,\n \"Phase\": {\n \"Name\": \"Waning Crescent\",\n \"NameLocalized\": \"Убывающий серп\",\n \"Emoji\": \"🌘\",\n \"IsWaxing\": false\n },\n \"Zodiac\": {\n \"Name\": \"Gemini\",\n \"NameLocalized\": \"Близнецы\",\n \"Emoji\": \"♊\"\n },\n \"MoonPosition\": {\n \"Time\": \"2025-09-17 00:00\",\n \"AzimuthDegrees\": 48.0345,\n \"AltitudeDegrees\": -0.14735,\n \"Direction\": \"NE\",\n \"DistanceKm\": 380020.57994\n }\n },\n \"MoonDaysDetailed\": {\n \"Count\": 2,\n \"Day\": [\n {\n \"Begin\": \"2025-09-15 22:37\",\n \"IsBeginExists\": true,\n \"End\": \"2025-09-16 23:56\",\n \"IsEndExists\": true\n },\n {\n \"Begin\": \"2025-09-16 23:56\",\n \"IsBeginExists\": true,\n \"IsEndExists\": false\n }\n ]\n },\n \"ZodiacDetailed\": {\n \"Count\": 1,\n \"Zodiac\": [\n {\n \"Name\": \"Gemini\",\n \"NameLocalized\": \"Близнецы\",\n \"Emoji\": \"♊\",\n \"Begin\": \"2025-09-14 23:07\",\n \"End\": \"2025-09-17 11:07\"\n }\n ]\n },\n \"MoonRiseAndSet\": {\n \"IsMoonRise\": true,\n \"IsMoonSet\": true,\n \"IsMeridian\": true,\n \"Moonrise\": {\n \"Time\": \"2025-09-16 23:56\",\n \"AzimuthDegrees\": 47.31764,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"NE\",\n \"DistanceKm\": 380011.3104\n },\n \"Moonset\": {\n \"Time\": \"2025-09-16 16:29\",\n \"AzimuthDegrees\": 314.4689,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"NW\",\n \"DistanceKm\": 378931.34559\n },\n \"Meridian\": {\n \"Time\": \"2025-09-16 07:40\",\n \"AzimuthDegrees\": 180,\n \"AltitudeDegrees\": 65.7,\n \"Direction\": \"S\",\n \"DistanceKm\": 377658.15629\n }\n }\n}" + }, + { + "name": "moonPhaseTimestamp — timestamp timeFormat", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/v1/moonPhaseTimestamp?utc=UTC+5&lang=ru&precision=5&latitude=51.1655&longitude=71.4272×tamp=1758045697&timeFormat=timestamp", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "v1", + "moonPhaseTimestamp" + ], + "query": [ + { + "key": "utc", + "value": "UTC+5", + "description": "UTC in format UTC+7, UTC+09:30, -3" + }, + { + "key": "lang", + "value": "ru", + "description": "Values available: (\"en\", \"es\", \"fr\", \"de\", \"ru\", \"jp\")" + }, + { + "key": "precision", + "value": "5", + "description": "How many digits after . will be in output. Allowed range: [1, 20]" + }, + { + "key": "latitude", + "value": "51.1655", + "description": "Latitude of viewer's place. Used for moon position calculations: MoonDaysDetailed, MoonRiseAndSet, and MoonPosition object" + }, + { + "key": "longitude", + "value": "71.4272", + "description": "Longitude of viewer's place. Used for moon position calculations: MoonDaysDetailed, MoonRiseAndSet, and MoonPosition object" + }, + { + "key": "timestamp", + "value": "1758045697", + "description": "Timestamp for calculations. Current, if not specified" + }, + { + "key": "timeFormat", + "value": "timestamp", + "description": "Supports: \"ISO\" (default), \"timestamp\" any Go time format directives (without UTC), for example: \"Mon, 02 Jan 2006 15:04:05\"" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Server", + "value": "Fiber" + }, + { + "key": "Date", + "value": "Sun, 16 Nov 2025 18:24:22 GMT" + }, + { + "key": "Content-Type", + "value": "application/json", + "name": "Content-Type", + "description": "", + "type": "text" + }, + { + "key": "Content-Length", + "value": "1895" + } + ], + "cookie": [], + "body": "{\n \"BeginDay\": {\n \"MoonDays\": 23.53674,\n \"Illumination\": 38.2726,\n \"Phase\": {\n \"Name\": \"Waning Crescent\",\n \"NameLocalized\": \"Убывающий серп\",\n \"Emoji\": \"🌘\",\n \"IsWaxing\": false\n },\n \"Zodiac\": {\n \"Name\": \"Gemini\",\n \"NameLocalized\": \"Близнецы\",\n \"Emoji\": \"♊\"\n },\n \"MoonPosition\": {\n \"Time\": 1757962800,\n \"AzimuthDegrees\": 57.08873,\n \"AltitudeDegrees\": 8.79646,\n \"Direction\": \"ENE\",\n \"DistanceKm\": 376559.88437\n }\n },\n \"CurrentState\": {\n \"MoonDays\": 24.49619,\n \"Illumination\": 28.30607,\n \"Phase\": {\n \"Name\": \"Waning Crescent\",\n \"NameLocalized\": \"Убывающий серп\",\n \"Emoji\": \"🌘\",\n \"IsWaxing\": false\n },\n \"Zodiac\": {\n \"Name\": \"Gemini\",\n \"NameLocalized\": \"Близнецы\",\n \"Emoji\": \"♊\"\n },\n \"MoonPosition\": {\n \"Time\": 1758045697,\n \"AzimuthDegrees\": 36.77206,\n \"AltitudeDegrees\": -5.96783,\n \"Direction\": \"NE\",\n \"DistanceKm\": 379879.05898\n }\n },\n \"EndDay\": {\n \"MoonDays\": 24.53674,\n \"Illumination\": 27.90729,\n \"Phase\": {\n \"Name\": \"Waning Crescent\",\n \"NameLocalized\": \"Убывающий серп\",\n \"Emoji\": \"🌘\",\n \"IsWaxing\": false\n },\n \"Zodiac\": {\n \"Name\": \"Gemini\",\n \"NameLocalized\": \"Близнецы\",\n \"Emoji\": \"♊\"\n },\n \"MoonPosition\": {\n \"Time\": 1758049200,\n \"AzimuthDegrees\": 48.0345,\n \"AltitudeDegrees\": -0.14735,\n \"Direction\": \"NE\",\n \"DistanceKm\": 380020.57994\n }\n },\n \"MoonDaysDetailed\": {\n \"Count\": 2,\n \"Day\": [\n {\n \"Begin\": 1757957865,\n \"IsBeginExists\": true,\n \"End\": 1758048970,\n \"IsEndExists\": true\n },\n {\n \"Begin\": 1758048970,\n \"IsBeginExists\": true,\n \"IsEndExists\": false\n }\n ]\n },\n \"ZodiacDetailed\": {\n \"Count\": 1,\n \"Zodiac\": [\n {\n \"Name\": \"Gemini\",\n \"NameLocalized\": \"Близнецы\",\n \"Emoji\": \"♊\",\n \"Begin\": 1757873226,\n \"End\": 1758089226\n }\n ]\n },\n \"MoonRiseAndSet\": {\n \"IsMoonRise\": true,\n \"IsMoonSet\": true,\n \"IsMeridian\": true,\n \"Moonrise\": {\n \"Time\": 1758048970,\n \"AzimuthDegrees\": 47.31764,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"NE\",\n \"DistanceKm\": 380011.3104\n },\n \"Moonset\": {\n \"Time\": 1758022192,\n \"AzimuthDegrees\": 314.4689,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"NW\",\n \"DistanceKm\": 378931.34559\n },\n \"Meridian\": {\n \"Time\": 1757990436,\n \"AzimuthDegrees\": 180,\n \"AltitudeDegrees\": 65.7,\n \"Direction\": \"S\",\n \"DistanceKm\": 377658.15629\n }\n }\n}" + } + ] + } + ] + }, + { + "name": "Moon — Detailed information for month", + "item": [ + { + "name": "Get moon rises, moon sets and meridians monthly", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/v1/moonPositionMonthly?utc=UTC+5&latitude=51.1655&longitude=71.4272&year=2023&month=3&precision=5&timeFormat=2006-01-02 15:04", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "v1", + "moonPositionMonthly" + ], + "query": [ + { + "key": "utc", + "value": "UTC+5", + "description": "UTC in format UTC+7, UTC+09:30, -3" + }, + { + "key": "latitude", + "value": "51.1655", + "description": "Latitude of viewer's place. Used for moon position calculations: MoonDaysDetailed, MoonRiseAndSet, and MoonPosition object" + }, + { + "key": "longitude", + "value": "71.4272", + "description": "Longitude of viewer's place. Used for moon position calculations: MoonDaysDetailed, MoonRiseAndSet, and MoonPosition object" + }, + { + "key": "year", + "value": "2023", + "description": "Format: YYYY Allowed range: [1899, 2053]. Current, if not specified" + }, + { + "key": "month", + "value": "3", + "description": "Format: M or MM. Allowed range: [1, 12]. Current, if not specified" + }, + { + "key": "precision", + "value": "5", + "description": "How many digits after . will be in output. Allowed range: [1, 20]" + }, + { + "key": "timeFormat", + "value": "2006-01-02 15:04", + "description": "Supports: \"ISO\" (default), \"timestamp\" any Go time format directives (without UTC), for example: \"Mon, 02 Jan 2006 15:04:05\"" + } + ] + } + }, + "response": [ + { + "name": "moonPositionMonthly — ok", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/v1/moonPositionMonthly?utc=UTC+5&latitude=51.1655&longitude=71.4272&year=2023&month=3&precision=5", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "v1", + "moonPositionMonthly" + ], + "query": [ + { + "key": "utc", + "value": "UTC+5", + "description": "UTC in format UTC+7, UTC+09:30, -3" + }, + { + "key": "latitude", + "value": "51.1655", + "description": "Latitude of viewer's place. Used for moon position calculations: MoonDaysDetailed, MoonRiseAndSet, and MoonPosition object" + }, + { + "key": "longitude", + "value": "71.4272", + "description": "Longitude of viewer's place. Used for moon position calculations: MoonDaysDetailed, MoonRiseAndSet, and MoonPosition object" + }, + { + "key": "year", + "value": "2023", + "description": "Format: YYYY Allowed range: [1899, 2053]. Current, if not specified" + }, + { + "key": "month", + "value": "3", + "description": "Format: M or MM. Allowed range: [1, 12]. Current, if not specified" + }, + { + "key": "precision", + "value": "5", + "description": "How many digits after . will be in output. Allowed range: [1, 20]" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Server", + "value": "Fiber" + }, + { + "key": "Date", + "value": "Sun, 16 Nov 2025 15:25:52 GMT" + }, + { + "key": "Content-Type", + "value": "application/json", + "description": "", + "type": "text" + }, + { + "key": "Content-Length", + "value": "17334" + } + ], + "cookie": [ + { + "expires": "Invalid Date", + "domain": "", + "path": "" + } + ], + "body": "[\n {\n \"Date\": \"2023-03-01\",\n \"IsMoonRise\": true,\n \"IsMoonSet\": true,\n \"IsMeridian\": true,\n \"Moonrise\": {\n \"Time\": \"2023-03-01T11:07:37+05:00\",\n \"AzimuthDegrees\": 42.8762,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"NE\",\n \"DistanceKm\": 402636.75966\n },\n \"Moonset\": {\n \"Time\": \"2023-03-01T04:10:07+05:00\",\n \"AzimuthDegrees\": 316.74613,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"NW\",\n \"DistanceKm\": 401798.89266\n },\n \"Meridian\": {\n \"Time\": \"2023-03-01T20:05:30+05:00\",\n \"AzimuthDegrees\": 180,\n \"AltitudeDegrees\": 66.2,\n \"Direction\": \"S\",\n \"DistanceKm\": 403572.05151\n }\n },\n {\n \"Date\": \"2023-03-02\",\n \"IsMoonRise\": true,\n \"IsMoonSet\": true,\n \"IsMeridian\": true,\n \"Moonrise\": {\n \"Time\": \"2023-03-02T12:01:07+05:00\",\n \"AzimuthDegrees\": 43.38104,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"NE\",\n \"DistanceKm\": 404836.13007\n },\n \"Moonset\": {\n \"Time\": \"2023-03-02T05:03:00+05:00\",\n \"AzimuthDegrees\": 317.04922,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"NW\",\n \"DistanceKm\": 404345.126\n },\n \"Meridian\": {\n \"Time\": \"2023-03-02T20:56:36+05:00\",\n \"AzimuthDegrees\": 180,\n \"AltitudeDegrees\": 65.4,\n \"Direction\": \"S\",\n \"DistanceKm\": 405326.66664\n }\n },\n {\n \"Date\": \"2023-03-03\",\n \"IsMoonRise\": true,\n \"IsMoonSet\": true,\n \"IsMeridian\": true,\n \"Moonrise\": {\n \"Time\": \"2023-03-03T13:04:19+05:00\",\n \"AzimuthDegrees\": 46.62247,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"NE\",\n \"DistanceKm\": 405833.52922\n },\n \"Moonset\": {\n \"Time\": \"2023-03-03T05:43:39+05:00\",\n \"AzimuthDegrees\": 314.58446,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"NW\",\n \"DistanceKm\": 405661.87336\n },\n \"Meridian\": {\n \"Time\": \"2023-03-03T21:46:07+05:00\",\n \"AzimuthDegrees\": 180,\n \"AltitudeDegrees\": 63.4,\n \"Direction\": \"S\",\n \"DistanceKm\": 405914.02206\n }\n },\n {\n \"Date\": \"2023-03-04\",\n \"IsMoonRise\": true,\n \"IsMoonSet\": true,\n \"IsMeridian\": true,\n \"Moonrise\": {\n \"Time\": \"2023-03-04T14:13:38+05:00\",\n \"AzimuthDegrees\": 52.09931,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"NE\",\n \"DistanceKm\": 405724.54322\n },\n \"Moonset\": {\n \"Time\": \"2023-03-04T06:13:52+05:00\",\n \"AzimuthDegrees\": 309.84464,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"NW\",\n \"DistanceKm\": 405870.41007\n },\n \"Meridian\": {\n \"Time\": \"2023-03-04T22:33:27+05:00\",\n \"AzimuthDegrees\": 180,\n \"AltitudeDegrees\": 60.1,\n \"Direction\": \"S\",\n \"DistanceKm\": 405470.71269\n }\n },\n {\n \"Date\": \"2023-03-05\",\n \"IsMoonRise\": true,\n \"IsMoonSet\": true,\n \"IsMeridian\": true,\n \"Moonrise\": {\n \"Time\": \"2023-03-05T15:25:33+05:00\",\n \"AzimuthDegrees\": 59.20503,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"ENE\",\n \"DistanceKm\": 404665.50003\n },\n \"Moonset\": {\n \"Time\": \"2023-03-05T06:36:23+05:00\",\n \"AzimuthDegrees\": 303.43187,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"WNW\",\n \"DistanceKm\": 405132.86805\n },\n \"Meridian\": {\n \"Time\": \"2023-03-05T23:18:28+05:00\",\n \"AzimuthDegrees\": 180,\n \"AltitudeDegrees\": 55.9,\n \"Direction\": \"S\",\n \"DistanceKm\": 404168.13916\n }\n },\n {\n \"Date\": \"2023-03-06\",\n \"IsMoonRise\": true,\n \"IsMoonSet\": true,\n \"IsMeridian\": false,\n \"Moonrise\": {\n \"Time\": \"2023-03-06T16:37:52+05:00\",\n \"AzimuthDegrees\": 67.43208,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"ENE\",\n \"DistanceKm\": 402838.67123\n },\n \"Moonset\": {\n \"Time\": \"2023-03-06T06:53:44+05:00\",\n \"AzimuthDegrees\": 295.85243,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"WNW\",\n \"DistanceKm\": 403623.69367\n }\n },\n {\n \"Date\": \"2023-03-07\",\n \"IsMoonRise\": true,\n \"IsMoonSet\": true,\n \"IsMeridian\": true,\n \"Moonrise\": {\n \"Time\": \"2023-03-07T17:49:47+05:00\",\n \"AzimuthDegrees\": 76.41149,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"ENE\",\n \"DistanceKm\": 400418.46475\n },\n \"Moonset\": {\n \"Time\": \"2023-03-07T07:07:49+05:00\",\n \"AzimuthDegrees\": 287.47458,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"WNW\",\n \"DistanceKm\": 401508.60505\n },\n \"Meridian\": {\n \"Time\": \"2023-03-07T00:01:28+05:00\",\n \"AzimuthDegrees\": 180,\n \"AltitudeDegrees\": 50.9,\n \"Direction\": \"S\",\n \"DistanceKm\": 402183.01801\n }\n },\n {\n \"Date\": \"2023-03-08\",\n \"IsMoonRise\": true,\n \"IsMoonSet\": true,\n \"IsMeridian\": true,\n \"Moonrise\": {\n \"Time\": \"2023-03-08T19:01:36+05:00\",\n \"AzimuthDegrees\": 85.87566,\n \"AltitudeDegrees\": -0.56666,\n \"Direction\": \"E\",\n \"DistanceKm\": 397547.14825\n },\n \"Moonset\": {\n \"Time\": \"2023-03-08T07:20:00+05:00\",\n \"AzimuthDegrees\": 278.56217,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"W\",\n \"DistanceKm\": 398928.36539\n },\n \"Meridian\": {\n \"Time\": \"2023-03-08T00:43:06+05:00\",\n \"AzimuthDegrees\": 180,\n \"AltitudeDegrees\": 45.4,\n \"Direction\": \"S\",\n \"DistanceKm\": 399673.27308\n }\n },\n {\n \"Date\": \"2023-03-09\",\n \"IsMoonRise\": true,\n \"IsMoonSet\": true,\n \"IsMeridian\": true,\n \"Moonrise\": {\n \"Time\": \"2023-03-09T20:14:11+05:00\",\n \"AzimuthDegrees\": 95.60853,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"E\",\n \"DistanceKm\": 394323.19311\n },\n \"Moonset\": {\n \"Time\": \"2023-03-09T07:31:23+05:00\",\n \"AzimuthDegrees\": 269.31953,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"W\",\n \"DistanceKm\": 395988.3718\n },\n \"Meridian\": {\n \"Time\": \"2023-03-09T01:24:12+05:00\",\n \"AzimuthDegrees\": 180,\n \"AltitudeDegrees\": 39.4,\n \"Direction\": \"S\",\n \"DistanceKm\": 396761.88573\n }\n },\n {\n \"Date\": \"2023-03-10\",\n \"IsMoonRise\": true,\n \"IsMoonSet\": true,\n \"IsMeridian\": true,\n \"Moonrise\": {\n \"Time\": \"2023-03-10T21:28:42+05:00\",\n \"AzimuthDegrees\": 105.39738,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"ESE\",\n \"DistanceKm\": 390803.12388\n },\n \"Moonset\": {\n \"Time\": \"2023-03-10T07:42:57+05:00\",\n \"AzimuthDegrees\": 259.93073,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"W\",\n \"DistanceKm\": 392756.20131\n },\n \"Meridian\": {\n \"Time\": \"2023-03-10T02:05:44+05:00\",\n \"AzimuthDegrees\": 180,\n \"AltitudeDegrees\": 33.4,\n \"Direction\": \"S\",\n \"DistanceKm\": 393530.65092\n }\n },\n {\n \"Date\": \"2023-03-11\",\n \"IsMoonRise\": true,\n \"IsMoonSet\": true,\n \"IsMeridian\": true,\n \"Moonrise\": {\n \"Time\": \"2023-03-11T22:46:09+05:00\",\n \"AzimuthDegrees\": 114.97706,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"ESE\",\n \"DistanceKm\": 387016.85411\n },\n \"Moonset\": {\n \"Time\": \"2023-03-11T07:55:44+05:00\",\n \"AzimuthDegrees\": 250.59757,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"WSW\",\n \"DistanceKm\": 389268.48137\n },\n \"Meridian\": {\n \"Time\": \"2023-03-11T02:48:49+05:00\",\n \"AzimuthDegrees\": 180,\n \"AltitudeDegrees\": 27.5,\n \"Direction\": \"S\",\n \"DistanceKm\": 390025.04685\n }\n },\n {\n \"Date\": \"2023-03-12\",\n \"IsMoonRise\": false,\n \"IsMoonSet\": true,\n \"IsMeridian\": true,\n \"Moonset\": {\n \"Time\": \"2023-03-12T08:11:09+05:00\",\n \"AzimuthDegrees\": 241.58881,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"WSW\",\n \"DistanceKm\": 385546.82937\n },\n \"Meridian\": {\n \"Time\": \"2023-03-12T03:34:35+05:00\",\n \"AzimuthDegrees\": 180,\n \"AltitudeDegrees\": 21.9,\n \"Direction\": \"S\",\n \"DistanceKm\": 386270.22231\n }\n },\n {\n \"Date\": \"2023-03-13\",\n \"IsMoonRise\": true,\n \"IsMoonSet\": true,\n \"IsMeridian\": true,\n \"Moonrise\": {\n \"Time\": \"2023-03-13T00:06:52+05:00\",\n \"AzimuthDegrees\": 123.94721,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"SE\",\n \"DistanceKm\": 382995.32957\n },\n \"Moonset\": {\n \"Time\": \"2023-03-13T08:31:18+05:00\",\n \"AzimuthDegrees\": 233.31784,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"SW\",\n \"DistanceKm\": 381620.77804\n },\n \"Meridian\": {\n \"Time\": \"2023-03-13T04:24:06+05:00\",\n \"AzimuthDegrees\": 180,\n \"AltitudeDegrees\": 17,\n \"Direction\": \"S\",\n \"DistanceKm\": 382296.46854\n }\n },\n {\n \"Date\": \"2023-03-14\",\n \"IsMoonRise\": true,\n \"IsMoonSet\": true,\n \"IsMeridian\": true,\n \"Moonrise\": {\n \"Time\": \"2023-03-14T01:29:17+05:00\",\n \"AzimuthDegrees\": 131.64699,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"SE\",\n \"DistanceKm\": 378807.06957\n },\n \"Moonset\": {\n \"Time\": \"2023-03-14T08:59:32+05:00\",\n \"AzimuthDegrees\": 226.46039,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"SW\",\n \"DistanceKm\": 377554.30425\n },\n \"Meridian\": {\n \"Time\": \"2023-03-14T05:18:05+05:00\",\n \"AzimuthDegrees\": 180,\n \"AltitudeDegrees\": 13.1,\n \"Direction\": \"S\",\n \"DistanceKm\": 378170.5856\n }\n },\n {\n \"Date\": \"2023-03-15\",\n \"IsMoonRise\": true,\n \"IsMoonSet\": true,\n \"IsMeridian\": true,\n \"Moonrise\": {\n \"Time\": \"2023-03-15T02:48:45+05:00\",\n \"AzimuthDegrees\": 137.04254,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"SE\",\n \"DistanceKm\": 374594.67251\n },\n \"Moonset\": {\n \"Time\": \"2023-03-15T09:40:38+05:00\",\n \"AzimuthDegrees\": 222.05405,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"SW\",\n \"DistanceKm\": 373473.15308\n },\n \"Meridian\": {\n \"Time\": \"2023-03-15T06:16:32+05:00\",\n \"AzimuthDegrees\": 180,\n \"AltitudeDegrees\": 10.7,\n \"Direction\": \"S\",\n \"DistanceKm\": 374026.97617\n }\n },\n {\n \"Date\": \"2023-03-16\",\n \"IsMoonRise\": true,\n \"IsMoonSet\": true,\n \"IsMeridian\": true,\n \"Moonrise\": {\n \"Time\": \"2023-03-16T03:57:52+05:00\",\n \"AzimuthDegrees\": 138.9114,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"SE\",\n \"DistanceKm\": 370591.50029\n },\n \"Moonset\": {\n \"Time\": \"2023-03-16T10:39:26+05:00\",\n \"AzimuthDegrees\": 221.29657,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"SW\",\n \"DistanceKm\": 369592.67725\n },\n \"Meridian\": {\n \"Time\": \"2023-03-16T07:18:12+05:00\",\n \"AzimuthDegrees\": 180,\n \"AltitudeDegrees\": 10.1,\n \"Direction\": \"S\",\n \"DistanceKm\": 370088.60593\n }\n },\n {\n \"Date\": \"2023-03-17\",\n \"IsMoonRise\": true,\n \"IsMoonSet\": true,\n \"IsMeridian\": true,\n \"Moonrise\": {\n \"Time\": \"2023-03-17T04:51:03+05:00\",\n \"AzimuthDegrees\": 136.61246,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"SE\",\n \"DistanceKm\": 367098.86901\n },\n \"Moonset\": {\n \"Time\": \"2023-03-17T11:56:14+05:00\",\n \"AzimuthDegrees\": 224.76797,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"SW\",\n \"DistanceKm\": 366237.19817\n },\n \"Meridian\": {\n \"Time\": \"2023-03-17T08:20:51+05:00\",\n \"AzimuthDegrees\": 180,\n \"AltitudeDegrees\": 11.4,\n \"Direction\": \"S\",\n \"DistanceKm\": 366664.93323\n }\n },\n {\n \"Date\": \"2023-03-18\",\n \"IsMoonRise\": true,\n \"IsMoonSet\": true,\n \"IsMeridian\": true,\n \"Moonrise\": {\n \"Time\": \"2023-03-18T05:28:46+05:00\",\n \"AzimuthDegrees\": 130.65168,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"SE\",\n \"DistanceKm\": 364441.40172\n },\n \"Moonset\": {\n \"Time\": \"2023-03-18T13:24:50+05:00\",\n \"AzimuthDegrees\": 231.87919,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"SW\",\n \"DistanceKm\": 363812.28579\n },\n \"Meridian\": {\n \"Time\": \"2023-03-18T09:21:59+05:00\",\n \"AzimuthDegrees\": 180,\n \"AltitudeDegrees\": 14.8,\n \"Direction\": \"S\",\n \"DistanceKm\": 364117.71582\n }\n },\n {\n \"Date\": \"2023-03-19\",\n \"IsMoonRise\": true,\n \"IsMoonSet\": true,\n \"IsMeridian\": true,\n \"Moonrise\": {\n \"Time\": \"2023-03-19T05:55:20+05:00\",\n \"AzimuthDegrees\": 122.15123,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"ESE\",\n \"DistanceKm\": 362929.11813\n },\n \"Moonset\": {\n \"Time\": \"2023-03-19T14:57:13+05:00\",\n \"AzimuthDegrees\": 241.42982,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"WSW\",\n \"DistanceKm\": 362712.81832\n },\n \"Meridian\": {\n \"Time\": \"2023-03-19T10:19:54+05:00\",\n \"AzimuthDegrees\": 180,\n \"AltitudeDegrees\": 19.7,\n \"Direction\": \"S\",\n \"DistanceKm\": 362798.79835\n }\n },\n {\n \"Date\": \"2023-03-20\",\n \"IsMoonRise\": true,\n \"IsMoonSet\": true,\n \"IsMeridian\": true,\n \"Moonrise\": {\n \"Time\": \"2023-03-20T06:15:02+05:00\",\n \"AzimuthDegrees\": 112.14362,\n \"AltitudeDegrees\": -0.56666,\n \"Direction\": \"ESE\",\n \"DistanceKm\": 362812.63242\n },\n \"Moonset\": {\n \"Time\": \"2023-03-20T16:28:22+05:00\",\n \"AzimuthDegrees\": 252.32977,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"WSW\",\n \"DistanceKm\": 363219.08698\n },\n \"Meridian\": {\n \"Time\": \"2023-03-20T11:14:12+05:00\",\n \"AzimuthDegrees\": 180,\n \"AltitudeDegrees\": 25.9,\n \"Direction\": \"S\",\n \"DistanceKm\": 362976.42916\n }\n },\n {\n \"Date\": \"2023-03-21\",\n \"IsMoonRise\": true,\n \"IsMoonSet\": true,\n \"IsMeridian\": true,\n \"Moonrise\": {\n \"Time\": \"2023-03-21T06:30:54+05:00\",\n \"AzimuthDegrees\": 101.3864,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"ESE\",\n \"DistanceKm\": 364227.26916\n },\n \"Moonset\": {\n \"Time\": \"2023-03-21T17:56:40+05:00\",\n \"AzimuthDegrees\": 263.78338,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"W\",\n \"DistanceKm\": 365425.30425\n },\n \"Meridian\": {\n \"Time\": \"2023-03-21T12:05:25+05:00\",\n \"AzimuthDegrees\": 180,\n \"AltitudeDegrees\": 32.8,\n \"Direction\": \"S\",\n \"DistanceKm\": 364770.21284\n }\n },\n {\n \"Date\": \"2023-03-22\",\n \"IsMoonRise\": true,\n \"IsMoonSet\": true,\n \"IsMeridian\": true,\n \"Moonrise\": {\n \"Time\": \"2023-03-22T06:44:57+05:00\",\n \"AzimuthDegrees\": 90.43001,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"E\",\n \"DistanceKm\": 367149.18373\n },\n \"Moonset\": {\n \"Time\": \"2023-03-22T19:22:27+05:00\",\n \"AzimuthDegrees\": 275.21269,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"W\",\n \"DistanceKm\": 369210.60777\n },\n \"Meridian\": {\n \"Time\": \"2023-03-22T12:54:37+05:00\",\n \"AzimuthDegrees\": 180,\n \"AltitudeDegrees\": 39.9,\n \"Direction\": \"S\",\n \"DistanceKm\": 368112.88854\n }\n },\n {\n \"Date\": \"2023-03-23\",\n \"IsMoonRise\": true,\n \"IsMoonSet\": true,\n \"IsMeridian\": true,\n \"Moonrise\": {\n \"Time\": \"2023-03-23T06:58:42+05:00\",\n \"AzimuthDegrees\": 79.70263,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"E\",\n \"DistanceKm\": 371383.43121\n },\n \"Moonset\": {\n \"Time\": \"2023-03-23T20:46:38+05:00\",\n \"AzimuthDegrees\": 286.16029,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"WNW\",\n \"DistanceKm\": 374253.93367\n },\n \"Meridian\": {\n \"Time\": \"2023-03-23T13:43:00+05:00\",\n \"AzimuthDegrees\": 180,\n \"AltitudeDegrees\": 46.7,\n \"Direction\": \"S\",\n \"DistanceKm\": 372750.53254\n }\n },\n {\n \"Date\": \"2023-03-24\",\n \"IsMoonRise\": true,\n \"IsMoonSet\": true,\n \"IsMeridian\": true,\n \"Moonrise\": {\n \"Time\": \"2023-03-24T07:13:32+05:00\",\n \"AzimuthDegrees\": 69.57123,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"ENE\",\n \"DistanceKm\": 376588.54488\n },\n \"Moonset\": {\n \"Time\": \"2023-03-24T22:09:45+05:00\",\n \"AzimuthDegrees\": 296.21187,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"WNW\",\n \"DistanceKm\": 380086.26614\n },\n \"Meridian\": {\n \"Time\": \"2023-03-24T14:31:39+05:00\",\n \"AzimuthDegrees\": 180,\n \"AltitudeDegrees\": 52.9,\n \"Direction\": \"S\",\n \"DistanceKm\": 378280.3871\n }\n },\n {\n \"Date\": \"2023-03-25\",\n \"IsMoonRise\": true,\n \"IsMoonSet\": true,\n \"IsMeridian\": true,\n \"Moonrise\": {\n \"Time\": \"2023-03-25T07:30:56+05:00\",\n \"AzimuthDegrees\": 60.39425,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"ENE\",\n \"DistanceKm\": 382327.95573\n },\n \"Moonset\": {\n \"Time\": \"2023-03-25T23:31:14+05:00\",\n \"AzimuthDegrees\": 304.92579,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"NW\",\n \"DistanceKm\": 386164.32159\n },\n \"Meridian\": {\n \"Time\": \"2023-03-25T15:21:19+05:00\",\n \"AzimuthDegrees\": 180,\n \"AltitudeDegrees\": 58.2,\n \"Direction\": \"S\",\n \"DistanceKm\": 384213.14123\n }\n },\n {\n \"Date\": \"2023-03-26\",\n \"IsMoonRise\": true,\n \"IsMoonSet\": false,\n \"IsMeridian\": true,\n \"Moonrise\": {\n \"Time\": \"2023-03-26T07:52:49+05:00\",\n \"AzimuthDegrees\": 52.57818,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"NE\",\n \"DistanceKm\": 388131.21721\n },\n \"Meridian\": {\n \"Time\": \"2023-03-26T16:12:24+05:00\",\n \"AzimuthDegrees\": 180,\n \"AltitudeDegrees\": 62.3,\n \"Direction\": \"S\",\n \"DistanceKm\": 390041.63582\n }\n },\n {\n \"Date\": \"2023-03-27\",\n \"IsMoonRise\": true,\n \"IsMoonSet\": true,\n \"IsMeridian\": true,\n \"Moonrise\": {\n \"Time\": \"2023-03-27T08:21:40+05:00\",\n \"AzimuthDegrees\": 46.62563,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"NE\",\n \"DistanceKm\": 393548.92562\n },\n \"Moonset\": {\n \"Time\": \"2023-03-27T00:48:54+05:00\",\n \"AzimuthDegrees\": 311.77602,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"NW\",\n \"DistanceKm\": 391948.19405\n },\n \"Meridian\": {\n \"Time\": \"2023-03-27T17:04:41+05:00\",\n \"AzimuthDegrees\": 180,\n \"AltitudeDegrees\": 65,\n \"Direction\": \"S\",\n \"DistanceKm\": 395301.62304\n }\n },\n {\n \"Date\": \"2023-03-28\",\n \"IsMoonRise\": true,\n \"IsMoonSet\": true,\n \"IsMeridian\": true,\n \"Moonrise\": {\n \"Time\": \"2023-03-28T09:00:10+05:00\",\n \"AzimuthDegrees\": 43.11087,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"NE\",\n \"DistanceKm\": 398191.74953\n },\n \"Moonset\": {\n \"Time\": \"2023-03-28T01:59:01+05:00\",\n \"AzimuthDegrees\": 316.17036,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"NW\",\n \"DistanceKm\": 396971.11487\n },\n \"Meridian\": {\n \"Time\": \"2023-03-28T17:57:26+05:00\",\n \"AzimuthDegrees\": 180,\n \"AltitudeDegrees\": 66.3,\n \"Direction\": \"S\",\n \"DistanceKm\": 399617.2651\n }\n },\n {\n \"Date\": \"2023-03-29\",\n \"IsMoonRise\": true,\n \"IsMoonSet\": true,\n \"IsMeridian\": true,\n \"Moonrise\": {\n \"Time\": \"2023-03-29T09:50:05+05:00\",\n \"AzimuthDegrees\": 42.48507,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"NE\",\n \"DistanceKm\": 401753.75503\n },\n \"Moonset\": {\n \"Time\": \"2023-03-29T02:57:44+05:00\",\n \"AzimuthDegrees\": 317.64261,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"NW\",\n \"DistanceKm\": 400892.49384\n },\n \"Meridian\": {\n \"Time\": \"2023-03-29T18:49:36+05:00\",\n \"AzimuthDegrees\": 180,\n \"AltitudeDegrees\": 66.1,\n \"Direction\": \"S\",\n \"DistanceKm\": 402729.21577\n }\n },\n {\n \"Date\": \"2023-03-30\",\n \"IsMoonRise\": true,\n \"IsMoonSet\": true,\n \"IsMeridian\": true,\n \"Moonrise\": {\n \"Time\": \"2023-03-30T10:50:38+05:00\",\n \"AzimuthDegrees\": 44.77953,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"NE\",\n \"DistanceKm\": 404030.19632\n },\n \"Moonset\": {\n \"Time\": \"2023-03-30T03:43:20+05:00\",\n \"AzimuthDegrees\": 316.15045,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"NW\",\n \"DistanceKm\": 403521.433\n },\n \"Meridian\": {\n \"Time\": \"2023-03-30T19:40:09+05:00\",\n \"AzimuthDegrees\": 180,\n \"AltitudeDegrees\": 64.4,\n \"Direction\": \"S\",\n \"DistanceKm\": 404505.37243\n }\n },\n {\n \"Date\": \"2023-03-31\",\n \"IsMoonRise\": true,\n \"IsMoonSet\": true,\n \"IsMeridian\": true,\n \"Moonrise\": {\n \"Time\": \"2023-03-31T11:58:33+05:00\",\n \"AzimuthDegrees\": 49.55137,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"NE\",\n \"DistanceKm\": 404935.96867\n },\n \"Moonset\": {\n \"Time\": \"2023-03-31T04:17:06+05:00\",\n \"AzimuthDegrees\": 312.1322,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"NW\",\n \"DistanceKm\": 404804.48186\n },\n \"Meridian\": {\n \"Time\": \"2023-03-31T20:28:24+05:00\",\n \"AzimuthDegrees\": 180,\n \"AltitudeDegrees\": 61.6,\n \"Direction\": \"S\",\n \"DistanceKm\": 404936.05398\n }\n }\n]" + }, + { + "name": "moonPositionMonthly — error", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/v1/moonPositionMonthly?utc=UTC+5&latitude=51.1655&longitude=71.4272&year=9999&month=3&precision=5", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "v1", + "moonPositionMonthly" + ], + "query": [ + { + "key": "utc", + "value": "UTC+5", + "description": "UTC in format UTC+7, UTC+09:30, -3" + }, + { + "key": "latitude", + "value": "51.1655", + "description": "Latitude of viewer's place. Used for moon position calculations: MoonDaysDetailed, MoonRiseAndSet, and MoonPosition object" + }, + { + "key": "longitude", + "value": "71.4272", + "description": "Longitude of viewer's place. Used for moon position calculations: MoonDaysDetailed, MoonRiseAndSet, and MoonPosition object" + }, + { + "key": "year", + "value": "9999", + "description": "Format: YYYY Allowed range: [1899, 2053]. Current, if not specified" + }, + { + "key": "month", + "value": "3", + "description": "Format: M or MM. Allowed range: [1, 12]. Current, if not specified" + }, + { + "key": "precision", + "value": "5", + "description": "How many digits after . will be in output. Allowed range: [1, 20]" + } + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Server", + "value": "Fiber" + }, + { + "key": "Date", + "value": "Sun, 16 Nov 2025 15:26:10 GMT" + }, + { + "key": "Content-Type", + "value": "application/json", + "name": "Content-Type", + "description": "", + "type": "text" + }, + { + "key": "Content-Length", + "value": "136" + } + ], + "cookie": [], + "body": "{\n \"Status\": 400,\n \"Message\": \"[400 Bad Request] Invalid parameter format: ephemeris segment only covers dates 1899-07-29 through 2053-10-09\"\n}" + }, + { + "name": "moonPositionMonthly — custom timeFormat", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/v1/moonPositionMonthly?utc=UTC+5&latitude=51.1655&longitude=71.4272&year=2023&month=3&precision=5&timeFormat=2006-01-02 15:04", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "v1", + "moonPositionMonthly" + ], + "query": [ + { + "key": "utc", + "value": "UTC+5", + "description": "UTC in format UTC+7, UTC+09:30, -3" + }, + { + "key": "latitude", + "value": "51.1655", + "description": "Latitude of viewer's place. Used for moon position calculations: MoonDaysDetailed, MoonRiseAndSet, and MoonPosition object" + }, + { + "key": "longitude", + "value": "71.4272", + "description": "Longitude of viewer's place. Used for moon position calculations: MoonDaysDetailed, MoonRiseAndSet, and MoonPosition object" + }, + { + "key": "year", + "value": "2023", + "description": "Format: YYYY Allowed range: [1899, 2053]. Current, if not specified" + }, + { + "key": "month", + "value": "3", + "description": "Format: M or MM. Allowed range: [1, 12]. Current, if not specified" + }, + { + "key": "precision", + "value": "5", + "description": "How many digits after . will be in output. Allowed range: [1, 20]" + }, + { + "key": "timeFormat", + "value": "2006-01-02 15:04", + "description": "Supports: \"ISO\" (default), \"timestamp\" any Go time format directives (without UTC), for example: \"Mon, 02 Jan 2006 15:04:05\"" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "Text", + "header": [ + { + "key": "Server", + "value": "Fiber" + }, + { + "key": "Date", + "value": "Sun, 16 Nov 2025 18:28:02 GMT" + }, + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Content-Length", + "value": "14184" + } + ], + "cookie": [], + "body": "[\n {\n \"Date\": \"2023-03-01\",\n \"IsMoonRise\": true,\n \"IsMoonSet\": true,\n \"IsMeridian\": true,\n \"Moonrise\": {\n \"Time\": \"2023-03-01 11:07\",\n \"AzimuthDegrees\": 42.8762,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"NE\",\n \"DistanceKm\": 402636.75966\n },\n \"Moonset\": {\n \"Time\": \"2023-03-01 04:10\",\n \"AzimuthDegrees\": 316.74613,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"NW\",\n \"DistanceKm\": 401798.89266\n },\n \"Meridian\": {\n \"Time\": \"2023-03-01 20:05\",\n \"AzimuthDegrees\": 180,\n \"AltitudeDegrees\": 66.2,\n \"Direction\": \"S\",\n \"DistanceKm\": 403572.05151\n }\n },\n {\n \"Date\": \"2023-03-02\",\n \"IsMoonRise\": true,\n \"IsMoonSet\": true,\n \"IsMeridian\": true,\n \"Moonrise\": {\n \"Time\": \"2023-03-02 12:01\",\n \"AzimuthDegrees\": 43.38104,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"NE\",\n \"DistanceKm\": 404836.13007\n },\n \"Moonset\": {\n \"Time\": \"2023-03-02 05:03\",\n \"AzimuthDegrees\": 317.04922,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"NW\",\n \"DistanceKm\": 404345.126\n },\n \"Meridian\": {\n \"Time\": \"2023-03-02 20:56\",\n \"AzimuthDegrees\": 180,\n \"AltitudeDegrees\": 65.4,\n \"Direction\": \"S\",\n \"DistanceKm\": 405326.66664\n }\n },\n {\n \"Date\": \"2023-03-03\",\n \"IsMoonRise\": true,\n \"IsMoonSet\": true,\n \"IsMeridian\": true,\n \"Moonrise\": {\n \"Time\": \"2023-03-03 13:04\",\n \"AzimuthDegrees\": 46.62247,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"NE\",\n \"DistanceKm\": 405833.52922\n },\n \"Moonset\": {\n \"Time\": \"2023-03-03 05:43\",\n \"AzimuthDegrees\": 314.58446,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"NW\",\n \"DistanceKm\": 405661.87336\n },\n \"Meridian\": {\n \"Time\": \"2023-03-03 21:46\",\n \"AzimuthDegrees\": 180,\n \"AltitudeDegrees\": 63.4,\n \"Direction\": \"S\",\n \"DistanceKm\": 405914.02206\n }\n },\n {\n \"Date\": \"2023-03-04\",\n \"IsMoonRise\": true,\n \"IsMoonSet\": true,\n \"IsMeridian\": true,\n \"Moonrise\": {\n \"Time\": \"2023-03-04 14:13\",\n \"AzimuthDegrees\": 52.09931,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"NE\",\n \"DistanceKm\": 405724.54322\n },\n \"Moonset\": {\n \"Time\": \"2023-03-04 06:13\",\n \"AzimuthDegrees\": 309.84464,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"NW\",\n \"DistanceKm\": 405870.41007\n },\n \"Meridian\": {\n \"Time\": \"2023-03-04 22:33\",\n \"AzimuthDegrees\": 180,\n \"AltitudeDegrees\": 60.1,\n \"Direction\": \"S\",\n \"DistanceKm\": 405470.71269\n }\n },\n {\n \"Date\": \"2023-03-05\",\n \"IsMoonRise\": true,\n \"IsMoonSet\": true,\n \"IsMeridian\": true,\n \"Moonrise\": {\n \"Time\": \"2023-03-05 15:25\",\n \"AzimuthDegrees\": 59.20503,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"ENE\",\n \"DistanceKm\": 404665.50003\n },\n \"Moonset\": {\n \"Time\": \"2023-03-05 06:36\",\n \"AzimuthDegrees\": 303.43187,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"WNW\",\n \"DistanceKm\": 405132.86805\n },\n \"Meridian\": {\n \"Time\": \"2023-03-05 23:18\",\n \"AzimuthDegrees\": 180,\n \"AltitudeDegrees\": 55.9,\n \"Direction\": \"S\",\n \"DistanceKm\": 404168.13916\n }\n },\n {\n \"Date\": \"2023-03-06\",\n \"IsMoonRise\": true,\n \"IsMoonSet\": true,\n \"IsMeridian\": false,\n \"Moonrise\": {\n \"Time\": \"2023-03-06 16:37\",\n \"AzimuthDegrees\": 67.43208,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"ENE\",\n \"DistanceKm\": 402838.67123\n },\n \"Moonset\": {\n \"Time\": \"2023-03-06 06:53\",\n \"AzimuthDegrees\": 295.85243,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"WNW\",\n \"DistanceKm\": 403623.69367\n }\n },\n {\n \"Date\": \"2023-03-07\",\n \"IsMoonRise\": true,\n \"IsMoonSet\": true,\n \"IsMeridian\": true,\n \"Moonrise\": {\n \"Time\": \"2023-03-07 17:49\",\n \"AzimuthDegrees\": 76.41149,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"ENE\",\n \"DistanceKm\": 400418.46475\n },\n \"Moonset\": {\n \"Time\": \"2023-03-07 07:07\",\n \"AzimuthDegrees\": 287.47458,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"WNW\",\n \"DistanceKm\": 401508.60505\n },\n \"Meridian\": {\n \"Time\": \"2023-03-07 00:01\",\n \"AzimuthDegrees\": 180,\n \"AltitudeDegrees\": 50.9,\n \"Direction\": \"S\",\n \"DistanceKm\": 402183.01801\n }\n },\n {\n \"Date\": \"2023-03-08\",\n \"IsMoonRise\": true,\n \"IsMoonSet\": true,\n \"IsMeridian\": true,\n \"Moonrise\": {\n \"Time\": \"2023-03-08 19:01\",\n \"AzimuthDegrees\": 85.87566,\n \"AltitudeDegrees\": -0.56666,\n \"Direction\": \"E\",\n \"DistanceKm\": 397547.14825\n },\n \"Moonset\": {\n \"Time\": \"2023-03-08 07:20\",\n \"AzimuthDegrees\": 278.56217,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"W\",\n \"DistanceKm\": 398928.36539\n },\n \"Meridian\": {\n \"Time\": \"2023-03-08 00:43\",\n \"AzimuthDegrees\": 180,\n \"AltitudeDegrees\": 45.4,\n \"Direction\": \"S\",\n \"DistanceKm\": 399673.27308\n }\n },\n {\n \"Date\": \"2023-03-09\",\n \"IsMoonRise\": true,\n \"IsMoonSet\": true,\n \"IsMeridian\": true,\n \"Moonrise\": {\n \"Time\": \"2023-03-09 20:14\",\n \"AzimuthDegrees\": 95.60853,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"E\",\n \"DistanceKm\": 394323.19311\n },\n \"Moonset\": {\n \"Time\": \"2023-03-09 07:31\",\n \"AzimuthDegrees\": 269.31953,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"W\",\n \"DistanceKm\": 395988.3718\n },\n \"Meridian\": {\n \"Time\": \"2023-03-09 01:24\",\n \"AzimuthDegrees\": 180,\n \"AltitudeDegrees\": 39.4,\n \"Direction\": \"S\",\n \"DistanceKm\": 396761.88573\n }\n },\n {\n \"Date\": \"2023-03-10\",\n \"IsMoonRise\": true,\n \"IsMoonSet\": true,\n \"IsMeridian\": true,\n \"Moonrise\": {\n \"Time\": \"2023-03-10 21:28\",\n \"AzimuthDegrees\": 105.39738,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"ESE\",\n \"DistanceKm\": 390803.12388\n },\n \"Moonset\": {\n \"Time\": \"2023-03-10 07:42\",\n \"AzimuthDegrees\": 259.93073,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"W\",\n \"DistanceKm\": 392756.20131\n },\n \"Meridian\": {\n \"Time\": \"2023-03-10 02:05\",\n \"AzimuthDegrees\": 180,\n \"AltitudeDegrees\": 33.4,\n \"Direction\": \"S\",\n \"DistanceKm\": 393530.65092\n }\n },\n {\n \"Date\": \"2023-03-11\",\n \"IsMoonRise\": true,\n \"IsMoonSet\": true,\n \"IsMeridian\": true,\n \"Moonrise\": {\n \"Time\": \"2023-03-11 22:46\",\n \"AzimuthDegrees\": 114.97706,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"ESE\",\n \"DistanceKm\": 387016.85411\n },\n \"Moonset\": {\n \"Time\": \"2023-03-11 07:55\",\n \"AzimuthDegrees\": 250.59757,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"WSW\",\n \"DistanceKm\": 389268.48137\n },\n \"Meridian\": {\n \"Time\": \"2023-03-11 02:48\",\n \"AzimuthDegrees\": 180,\n \"AltitudeDegrees\": 27.5,\n \"Direction\": \"S\",\n \"DistanceKm\": 390025.04685\n }\n },\n {\n \"Date\": \"2023-03-12\",\n \"IsMoonRise\": false,\n \"IsMoonSet\": true,\n \"IsMeridian\": true,\n \"Moonset\": {\n \"Time\": \"2023-03-12 08:11\",\n \"AzimuthDegrees\": 241.58881,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"WSW\",\n \"DistanceKm\": 385546.82937\n },\n \"Meridian\": {\n \"Time\": \"2023-03-12 03:34\",\n \"AzimuthDegrees\": 180,\n \"AltitudeDegrees\": 21.9,\n \"Direction\": \"S\",\n \"DistanceKm\": 386270.22231\n }\n },\n {\n \"Date\": \"2023-03-13\",\n \"IsMoonRise\": true,\n \"IsMoonSet\": true,\n \"IsMeridian\": true,\n \"Moonrise\": {\n \"Time\": \"2023-03-13 00:06\",\n \"AzimuthDegrees\": 123.94721,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"SE\",\n \"DistanceKm\": 382995.32957\n },\n \"Moonset\": {\n \"Time\": \"2023-03-13 08:31\",\n \"AzimuthDegrees\": 233.31784,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"SW\",\n \"DistanceKm\": 381620.77804\n },\n \"Meridian\": {\n \"Time\": \"2023-03-13 04:24\",\n \"AzimuthDegrees\": 180,\n \"AltitudeDegrees\": 17,\n \"Direction\": \"S\",\n \"DistanceKm\": 382296.46854\n }\n },\n {\n \"Date\": \"2023-03-14\",\n \"IsMoonRise\": true,\n \"IsMoonSet\": true,\n \"IsMeridian\": true,\n \"Moonrise\": {\n \"Time\": \"2023-03-14 01:29\",\n \"AzimuthDegrees\": 131.64699,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"SE\",\n \"DistanceKm\": 378807.06957\n },\n \"Moonset\": {\n \"Time\": \"2023-03-14 08:59\",\n \"AzimuthDegrees\": 226.46039,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"SW\",\n \"DistanceKm\": 377554.30425\n },\n \"Meridian\": {\n \"Time\": \"2023-03-14 05:18\",\n \"AzimuthDegrees\": 180,\n \"AltitudeDegrees\": 13.1,\n \"Direction\": \"S\",\n \"DistanceKm\": 378170.5856\n }\n },\n {\n \"Date\": \"2023-03-15\",\n \"IsMoonRise\": true,\n \"IsMoonSet\": true,\n \"IsMeridian\": true,\n \"Moonrise\": {\n \"Time\": \"2023-03-15 02:48\",\n \"AzimuthDegrees\": 137.04254,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"SE\",\n \"DistanceKm\": 374594.67251\n },\n \"Moonset\": {\n \"Time\": \"2023-03-15 09:40\",\n \"AzimuthDegrees\": 222.05405,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"SW\",\n \"DistanceKm\": 373473.15308\n },\n \"Meridian\": {\n \"Time\": \"2023-03-15 06:16\",\n \"AzimuthDegrees\": 180,\n \"AltitudeDegrees\": 10.7,\n \"Direction\": \"S\",\n \"DistanceKm\": 374026.97617\n }\n },\n {\n \"Date\": \"2023-03-16\",\n \"IsMoonRise\": true,\n \"IsMoonSet\": true,\n \"IsMeridian\": true,\n \"Moonrise\": {\n \"Time\": \"2023-03-16 03:57\",\n \"AzimuthDegrees\": 138.9114,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"SE\",\n \"DistanceKm\": 370591.50029\n },\n \"Moonset\": {\n \"Time\": \"2023-03-16 10:39\",\n \"AzimuthDegrees\": 221.29657,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"SW\",\n \"DistanceKm\": 369592.67725\n },\n \"Meridian\": {\n \"Time\": \"2023-03-16 07:18\",\n \"AzimuthDegrees\": 180,\n \"AltitudeDegrees\": 10.1,\n \"Direction\": \"S\",\n \"DistanceKm\": 370088.60593\n }\n },\n {\n \"Date\": \"2023-03-17\",\n \"IsMoonRise\": true,\n \"IsMoonSet\": true,\n \"IsMeridian\": true,\n \"Moonrise\": {\n \"Time\": \"2023-03-17 04:51\",\n \"AzimuthDegrees\": 136.61246,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"SE\",\n \"DistanceKm\": 367098.86901\n },\n \"Moonset\": {\n \"Time\": \"2023-03-17 11:56\",\n \"AzimuthDegrees\": 224.76797,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"SW\",\n \"DistanceKm\": 366237.19817\n },\n \"Meridian\": {\n \"Time\": \"2023-03-17 08:20\",\n \"AzimuthDegrees\": 180,\n \"AltitudeDegrees\": 11.4,\n \"Direction\": \"S\",\n \"DistanceKm\": 366664.93323\n }\n },\n {\n \"Date\": \"2023-03-18\",\n \"IsMoonRise\": true,\n \"IsMoonSet\": true,\n \"IsMeridian\": true,\n \"Moonrise\": {\n \"Time\": \"2023-03-18 05:28\",\n \"AzimuthDegrees\": 130.65168,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"SE\",\n \"DistanceKm\": 364441.40172\n },\n \"Moonset\": {\n \"Time\": \"2023-03-18 13:24\",\n \"AzimuthDegrees\": 231.87919,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"SW\",\n \"DistanceKm\": 363812.28579\n },\n \"Meridian\": {\n \"Time\": \"2023-03-18 09:21\",\n \"AzimuthDegrees\": 180,\n \"AltitudeDegrees\": 14.8,\n \"Direction\": \"S\",\n \"DistanceKm\": 364117.71582\n }\n },\n {\n \"Date\": \"2023-03-19\",\n \"IsMoonRise\": true,\n \"IsMoonSet\": true,\n \"IsMeridian\": true,\n \"Moonrise\": {\n \"Time\": \"2023-03-19 05:55\",\n \"AzimuthDegrees\": 122.15123,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"ESE\",\n \"DistanceKm\": 362929.11813\n },\n \"Moonset\": {\n \"Time\": \"2023-03-19 14:57\",\n \"AzimuthDegrees\": 241.42982,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"WSW\",\n \"DistanceKm\": 362712.81832\n },\n \"Meridian\": {\n \"Time\": \"2023-03-19 10:19\",\n \"AzimuthDegrees\": 180,\n \"AltitudeDegrees\": 19.7,\n \"Direction\": \"S\",\n \"DistanceKm\": 362798.79835\n }\n },\n {\n \"Date\": \"2023-03-20\",\n \"IsMoonRise\": true,\n \"IsMoonSet\": true,\n \"IsMeridian\": true,\n \"Moonrise\": {\n \"Time\": \"2023-03-20 06:15\",\n \"AzimuthDegrees\": 112.14362,\n \"AltitudeDegrees\": -0.56666,\n \"Direction\": \"ESE\",\n \"DistanceKm\": 362812.63242\n },\n \"Moonset\": {\n \"Time\": \"2023-03-20 16:28\",\n \"AzimuthDegrees\": 252.32977,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"WSW\",\n \"DistanceKm\": 363219.08698\n },\n \"Meridian\": {\n \"Time\": \"2023-03-20 11:14\",\n \"AzimuthDegrees\": 180,\n \"AltitudeDegrees\": 25.9,\n \"Direction\": \"S\",\n \"DistanceKm\": 362976.42916\n }\n },\n {\n \"Date\": \"2023-03-21\",\n \"IsMoonRise\": true,\n \"IsMoonSet\": true,\n \"IsMeridian\": true,\n \"Moonrise\": {\n \"Time\": \"2023-03-21 06:30\",\n \"AzimuthDegrees\": 101.3864,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"ESE\",\n \"DistanceKm\": 364227.26916\n },\n \"Moonset\": {\n \"Time\": \"2023-03-21 17:56\",\n \"AzimuthDegrees\": 263.78338,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"W\",\n \"DistanceKm\": 365425.30425\n },\n \"Meridian\": {\n \"Time\": \"2023-03-21 12:05\",\n \"AzimuthDegrees\": 180,\n \"AltitudeDegrees\": 32.8,\n \"Direction\": \"S\",\n \"DistanceKm\": 364770.21284\n }\n },\n {\n \"Date\": \"2023-03-22\",\n \"IsMoonRise\": true,\n \"IsMoonSet\": true,\n \"IsMeridian\": true,\n \"Moonrise\": {\n \"Time\": \"2023-03-22 06:44\",\n \"AzimuthDegrees\": 90.43001,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"E\",\n \"DistanceKm\": 367149.18373\n },\n \"Moonset\": {\n \"Time\": \"2023-03-22 19:22\",\n \"AzimuthDegrees\": 275.21269,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"W\",\n \"DistanceKm\": 369210.60777\n },\n \"Meridian\": {\n \"Time\": \"2023-03-22 12:54\",\n \"AzimuthDegrees\": 180,\n \"AltitudeDegrees\": 39.9,\n \"Direction\": \"S\",\n \"DistanceKm\": 368112.88854\n }\n },\n {\n \"Date\": \"2023-03-23\",\n \"IsMoonRise\": true,\n \"IsMoonSet\": true,\n \"IsMeridian\": true,\n \"Moonrise\": {\n \"Time\": \"2023-03-23 06:58\",\n \"AzimuthDegrees\": 79.70263,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"E\",\n \"DistanceKm\": 371383.43121\n },\n \"Moonset\": {\n \"Time\": \"2023-03-23 20:46\",\n \"AzimuthDegrees\": 286.16029,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"WNW\",\n \"DistanceKm\": 374253.93367\n },\n \"Meridian\": {\n \"Time\": \"2023-03-23 13:43\",\n \"AzimuthDegrees\": 180,\n \"AltitudeDegrees\": 46.7,\n \"Direction\": \"S\",\n \"DistanceKm\": 372750.53254\n }\n },\n {\n \"Date\": \"2023-03-24\",\n \"IsMoonRise\": true,\n \"IsMoonSet\": true,\n \"IsMeridian\": true,\n \"Moonrise\": {\n \"Time\": \"2023-03-24 07:13\",\n \"AzimuthDegrees\": 69.57123,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"ENE\",\n \"DistanceKm\": 376588.54488\n },\n \"Moonset\": {\n \"Time\": \"2023-03-24 22:09\",\n \"AzimuthDegrees\": 296.21187,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"WNW\",\n \"DistanceKm\": 380086.26614\n },\n \"Meridian\": {\n \"Time\": \"2023-03-24 14:31\",\n \"AzimuthDegrees\": 180,\n \"AltitudeDegrees\": 52.9,\n \"Direction\": \"S\",\n \"DistanceKm\": 378280.3871\n }\n },\n {\n \"Date\": \"2023-03-25\",\n \"IsMoonRise\": true,\n \"IsMoonSet\": true,\n \"IsMeridian\": true,\n \"Moonrise\": {\n \"Time\": \"2023-03-25 07:30\",\n \"AzimuthDegrees\": 60.39425,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"ENE\",\n \"DistanceKm\": 382327.95573\n },\n \"Moonset\": {\n \"Time\": \"2023-03-25 23:31\",\n \"AzimuthDegrees\": 304.92579,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"NW\",\n \"DistanceKm\": 386164.32159\n },\n \"Meridian\": {\n \"Time\": \"2023-03-25 15:21\",\n \"AzimuthDegrees\": 180,\n \"AltitudeDegrees\": 58.2,\n \"Direction\": \"S\",\n \"DistanceKm\": 384213.14123\n }\n },\n {\n \"Date\": \"2023-03-26\",\n \"IsMoonRise\": true,\n \"IsMoonSet\": false,\n \"IsMeridian\": true,\n \"Moonrise\": {\n \"Time\": \"2023-03-26 07:52\",\n \"AzimuthDegrees\": 52.57818,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"NE\",\n \"DistanceKm\": 388131.21721\n },\n \"Meridian\": {\n \"Time\": \"2023-03-26 16:12\",\n \"AzimuthDegrees\": 180,\n \"AltitudeDegrees\": 62.3,\n \"Direction\": \"S\",\n \"DistanceKm\": 390041.63582\n }\n },\n {\n \"Date\": \"2023-03-27\",\n \"IsMoonRise\": true,\n \"IsMoonSet\": true,\n \"IsMeridian\": true,\n \"Moonrise\": {\n \"Time\": \"2023-03-27 08:21\",\n \"AzimuthDegrees\": 46.62563,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"NE\",\n \"DistanceKm\": 393548.92562\n },\n \"Moonset\": {\n \"Time\": \"2023-03-27 00:48\",\n \"AzimuthDegrees\": 311.77602,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"NW\",\n \"DistanceKm\": 391948.19405\n },\n \"Meridian\": {\n \"Time\": \"2023-03-27 17:04\",\n \"AzimuthDegrees\": 180,\n \"AltitudeDegrees\": 65,\n \"Direction\": \"S\",\n \"DistanceKm\": 395301.62304\n }\n },\n {\n \"Date\": \"2023-03-28\",\n \"IsMoonRise\": true,\n \"IsMoonSet\": true,\n \"IsMeridian\": true,\n \"Moonrise\": {\n \"Time\": \"2023-03-28 09:00\",\n \"AzimuthDegrees\": 43.11087,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"NE\",\n \"DistanceKm\": 398191.74953\n },\n \"Moonset\": {\n \"Time\": \"2023-03-28 01:59\",\n \"AzimuthDegrees\": 316.17036,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"NW\",\n \"DistanceKm\": 396971.11487\n },\n \"Meridian\": {\n \"Time\": \"2023-03-28 17:57\",\n \"AzimuthDegrees\": 180,\n \"AltitudeDegrees\": 66.3,\n \"Direction\": \"S\",\n \"DistanceKm\": 399617.2651\n }\n },\n {\n \"Date\": \"2023-03-29\",\n \"IsMoonRise\": true,\n \"IsMoonSet\": true,\n \"IsMeridian\": true,\n \"Moonrise\": {\n \"Time\": \"2023-03-29 09:50\",\n \"AzimuthDegrees\": 42.48507,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"NE\",\n \"DistanceKm\": 401753.75503\n },\n \"Moonset\": {\n \"Time\": \"2023-03-29 02:57\",\n \"AzimuthDegrees\": 317.64261,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"NW\",\n \"DistanceKm\": 400892.49384\n },\n \"Meridian\": {\n \"Time\": \"2023-03-29 18:49\",\n \"AzimuthDegrees\": 180,\n \"AltitudeDegrees\": 66.1,\n \"Direction\": \"S\",\n \"DistanceKm\": 402729.21577\n }\n },\n {\n \"Date\": \"2023-03-30\",\n \"IsMoonRise\": true,\n \"IsMoonSet\": true,\n \"IsMeridian\": true,\n \"Moonrise\": {\n \"Time\": \"2023-03-30 10:50\",\n \"AzimuthDegrees\": 44.77953,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"NE\",\n \"DistanceKm\": 404030.19632\n },\n \"Moonset\": {\n \"Time\": \"2023-03-30 03:43\",\n \"AzimuthDegrees\": 316.15045,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"NW\",\n \"DistanceKm\": 403521.433\n },\n \"Meridian\": {\n \"Time\": \"2023-03-30 19:40\",\n \"AzimuthDegrees\": 180,\n \"AltitudeDegrees\": 64.4,\n \"Direction\": \"S\",\n \"DistanceKm\": 404505.37243\n }\n },\n {\n \"Date\": \"2023-03-31\",\n \"IsMoonRise\": true,\n \"IsMoonSet\": true,\n \"IsMeridian\": true,\n \"Moonrise\": {\n \"Time\": \"2023-03-31 11:58\",\n \"AzimuthDegrees\": 49.55137,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"NE\",\n \"DistanceKm\": 404935.96867\n },\n \"Moonset\": {\n \"Time\": \"2023-03-31 04:17\",\n \"AzimuthDegrees\": 312.1322,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"NW\",\n \"DistanceKm\": 404804.48186\n },\n \"Meridian\": {\n \"Time\": \"2023-03-31 20:28\",\n \"AzimuthDegrees\": 180,\n \"AltitudeDegrees\": 61.6,\n \"Direction\": \"S\",\n \"DistanceKm\": 404936.05398\n }\n }\n]" + }, + { + "name": "moonPositionMonthly — timestamp timeFormat", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/v1/moonPositionMonthly?utc=UTC+5&latitude=51.1655&longitude=71.4272&year=2023&month=3&precision=5&timeFormat=timestamp", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "v1", + "moonPositionMonthly" + ], + "query": [ + { + "key": "utc", + "value": "UTC+5", + "description": "UTC in format UTC+7, UTC+09:30, -3" + }, + { + "key": "latitude", + "value": "51.1655", + "description": "Latitude of viewer's place. Used for moon position calculations: MoonDaysDetailed, MoonRiseAndSet, and MoonPosition object" + }, + { + "key": "longitude", + "value": "71.4272", + "description": "Longitude of viewer's place. Used for moon position calculations: MoonDaysDetailed, MoonRiseAndSet, and MoonPosition object" + }, + { + "key": "year", + "value": "2023", + "description": "Format: YYYY Allowed range: [1899, 2053]. Current, if not specified" + }, + { + "key": "month", + "value": "3", + "description": "Format: M or MM. Allowed range: [1, 12]. Current, if not specified" + }, + { + "key": "precision", + "value": "5", + "description": "How many digits after . will be in output. Allowed range: [1, 20]" + }, + { + "key": "timeFormat", + "value": "timestamp", + "description": "Supports: \"ISO\" (default), \"timestamp\" any Go time format directives (without UTC), for example: \"Mon, 02 Jan 2006 15:04:05\"" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Server", + "value": "Fiber" + }, + { + "key": "Date", + "value": "Sun, 16 Nov 2025 18:27:20 GMT" + }, + { + "key": "Content-Type", + "value": "application/json", + "description": "", + "type": "text" + }, + { + "key": "Content-Length", + "value": "13464" + } + ], + "cookie": [ + { + "expires": "Invalid Date", + "domain": "", + "path": "" + } + ], + "body": "[\n {\n \"Date\": \"2023-03-01\",\n \"IsMoonRise\": true,\n \"IsMoonSet\": true,\n \"IsMeridian\": true,\n \"Moonrise\": {\n \"Time\": 1677650857,\n \"AzimuthDegrees\": 42.8762,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"NE\",\n \"DistanceKm\": 402636.75966\n },\n \"Moonset\": {\n \"Time\": 1677625807,\n \"AzimuthDegrees\": 316.74613,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"NW\",\n \"DistanceKm\": 401798.89266\n },\n \"Meridian\": {\n \"Time\": 1677683130,\n \"AzimuthDegrees\": 180,\n \"AltitudeDegrees\": 66.2,\n \"Direction\": \"S\",\n \"DistanceKm\": 403572.05151\n }\n },\n {\n \"Date\": \"2023-03-02\",\n \"IsMoonRise\": true,\n \"IsMoonSet\": true,\n \"IsMeridian\": true,\n \"Moonrise\": {\n \"Time\": 1677740467,\n \"AzimuthDegrees\": 43.38104,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"NE\",\n \"DistanceKm\": 404836.13007\n },\n \"Moonset\": {\n \"Time\": 1677715380,\n \"AzimuthDegrees\": 317.04922,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"NW\",\n \"DistanceKm\": 404345.126\n },\n \"Meridian\": {\n \"Time\": 1677772596,\n \"AzimuthDegrees\": 180,\n \"AltitudeDegrees\": 65.4,\n \"Direction\": \"S\",\n \"DistanceKm\": 405326.66664\n }\n },\n {\n \"Date\": \"2023-03-03\",\n \"IsMoonRise\": true,\n \"IsMoonSet\": true,\n \"IsMeridian\": true,\n \"Moonrise\": {\n \"Time\": 1677830659,\n \"AzimuthDegrees\": 46.62247,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"NE\",\n \"DistanceKm\": 405833.52922\n },\n \"Moonset\": {\n \"Time\": 1677804219,\n \"AzimuthDegrees\": 314.58446,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"NW\",\n \"DistanceKm\": 405661.87336\n },\n \"Meridian\": {\n \"Time\": 1677861967,\n \"AzimuthDegrees\": 180,\n \"AltitudeDegrees\": 63.4,\n \"Direction\": \"S\",\n \"DistanceKm\": 405914.02206\n }\n },\n {\n \"Date\": \"2023-03-04\",\n \"IsMoonRise\": true,\n \"IsMoonSet\": true,\n \"IsMeridian\": true,\n \"Moonrise\": {\n \"Time\": 1677921218,\n \"AzimuthDegrees\": 52.09931,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"NE\",\n \"DistanceKm\": 405724.54322\n },\n \"Moonset\": {\n \"Time\": 1677892432,\n \"AzimuthDegrees\": 309.84464,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"NW\",\n \"DistanceKm\": 405870.41007\n },\n \"Meridian\": {\n \"Time\": 1677951207,\n \"AzimuthDegrees\": 180,\n \"AltitudeDegrees\": 60.1,\n \"Direction\": \"S\",\n \"DistanceKm\": 405470.71269\n }\n },\n {\n \"Date\": \"2023-03-05\",\n \"IsMoonRise\": true,\n \"IsMoonSet\": true,\n \"IsMeridian\": true,\n \"Moonrise\": {\n \"Time\": 1678011933,\n \"AzimuthDegrees\": 59.20503,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"ENE\",\n \"DistanceKm\": 404665.50003\n },\n \"Moonset\": {\n \"Time\": 1677980183,\n \"AzimuthDegrees\": 303.43187,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"WNW\",\n \"DistanceKm\": 405132.86805\n },\n \"Meridian\": {\n \"Time\": 1678040308,\n \"AzimuthDegrees\": 180,\n \"AltitudeDegrees\": 55.9,\n \"Direction\": \"S\",\n \"DistanceKm\": 404168.13916\n }\n },\n {\n \"Date\": \"2023-03-06\",\n \"IsMoonRise\": true,\n \"IsMoonSet\": true,\n \"IsMeridian\": false,\n \"Moonrise\": {\n \"Time\": 1678102672,\n \"AzimuthDegrees\": 67.43208,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"ENE\",\n \"DistanceKm\": 402838.67123\n },\n \"Moonset\": {\n \"Time\": 1678067624,\n \"AzimuthDegrees\": 295.85243,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"WNW\",\n \"DistanceKm\": 403623.69367\n }\n },\n {\n \"Date\": \"2023-03-07\",\n \"IsMoonRise\": true,\n \"IsMoonSet\": true,\n \"IsMeridian\": true,\n \"Moonrise\": {\n \"Time\": 1678193387,\n \"AzimuthDegrees\": 76.41149,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"ENE\",\n \"DistanceKm\": 400418.46475\n },\n \"Moonset\": {\n \"Time\": 1678154869,\n \"AzimuthDegrees\": 287.47458,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"WNW\",\n \"DistanceKm\": 401508.60505\n },\n \"Meridian\": {\n \"Time\": 1678129288,\n \"AzimuthDegrees\": 180,\n \"AltitudeDegrees\": 50.9,\n \"Direction\": \"S\",\n \"DistanceKm\": 402183.01801\n }\n },\n {\n \"Date\": \"2023-03-08\",\n \"IsMoonRise\": true,\n \"IsMoonSet\": true,\n \"IsMeridian\": true,\n \"Moonrise\": {\n \"Time\": 1678284096,\n \"AzimuthDegrees\": 85.87566,\n \"AltitudeDegrees\": -0.56666,\n \"Direction\": \"E\",\n \"DistanceKm\": 397547.14825\n },\n \"Moonset\": {\n \"Time\": 1678242000,\n \"AzimuthDegrees\": 278.56217,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"W\",\n \"DistanceKm\": 398928.36539\n },\n \"Meridian\": {\n \"Time\": 1678218186,\n \"AzimuthDegrees\": 180,\n \"AltitudeDegrees\": 45.4,\n \"Direction\": \"S\",\n \"DistanceKm\": 399673.27308\n }\n },\n {\n \"Date\": \"2023-03-09\",\n \"IsMoonRise\": true,\n \"IsMoonSet\": true,\n \"IsMeridian\": true,\n \"Moonrise\": {\n \"Time\": 1678374851,\n \"AzimuthDegrees\": 95.60853,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"E\",\n \"DistanceKm\": 394323.19311\n },\n \"Moonset\": {\n \"Time\": 1678329083,\n \"AzimuthDegrees\": 269.31953,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"W\",\n \"DistanceKm\": 395988.3718\n },\n \"Meridian\": {\n \"Time\": 1678307052,\n \"AzimuthDegrees\": 180,\n \"AltitudeDegrees\": 39.4,\n \"Direction\": \"S\",\n \"DistanceKm\": 396761.88573\n }\n },\n {\n \"Date\": \"2023-03-10\",\n \"IsMoonRise\": true,\n \"IsMoonSet\": true,\n \"IsMeridian\": true,\n \"Moonrise\": {\n \"Time\": 1678465722,\n \"AzimuthDegrees\": 105.39738,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"ESE\",\n \"DistanceKm\": 390803.12388\n },\n \"Moonset\": {\n \"Time\": 1678416177,\n \"AzimuthDegrees\": 259.93073,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"W\",\n \"DistanceKm\": 392756.20131\n },\n \"Meridian\": {\n \"Time\": 1678395944,\n \"AzimuthDegrees\": 180,\n \"AltitudeDegrees\": 33.4,\n \"Direction\": \"S\",\n \"DistanceKm\": 393530.65092\n }\n },\n {\n \"Date\": \"2023-03-11\",\n \"IsMoonRise\": true,\n \"IsMoonSet\": true,\n \"IsMeridian\": true,\n \"Moonrise\": {\n \"Time\": 1678556769,\n \"AzimuthDegrees\": 114.97706,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"ESE\",\n \"DistanceKm\": 387016.85411\n },\n \"Moonset\": {\n \"Time\": 1678503344,\n \"AzimuthDegrees\": 250.59757,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"WSW\",\n \"DistanceKm\": 389268.48137\n },\n \"Meridian\": {\n \"Time\": 1678484929,\n \"AzimuthDegrees\": 180,\n \"AltitudeDegrees\": 27.5,\n \"Direction\": \"S\",\n \"DistanceKm\": 390025.04685\n }\n },\n {\n \"Date\": \"2023-03-12\",\n \"IsMoonRise\": false,\n \"IsMoonSet\": true,\n \"IsMeridian\": true,\n \"Moonset\": {\n \"Time\": 1678590669,\n \"AzimuthDegrees\": 241.58881,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"WSW\",\n \"DistanceKm\": 385546.82937\n },\n \"Meridian\": {\n \"Time\": 1678574075,\n \"AzimuthDegrees\": 180,\n \"AltitudeDegrees\": 21.9,\n \"Direction\": \"S\",\n \"DistanceKm\": 386270.22231\n }\n },\n {\n \"Date\": \"2023-03-13\",\n \"IsMoonRise\": true,\n \"IsMoonSet\": true,\n \"IsMeridian\": true,\n \"Moonrise\": {\n \"Time\": 1678648012,\n \"AzimuthDegrees\": 123.94721,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"SE\",\n \"DistanceKm\": 382995.32957\n },\n \"Moonset\": {\n \"Time\": 1678678278,\n \"AzimuthDegrees\": 233.31784,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"SW\",\n \"DistanceKm\": 381620.77804\n },\n \"Meridian\": {\n \"Time\": 1678663446,\n \"AzimuthDegrees\": 180,\n \"AltitudeDegrees\": 17,\n \"Direction\": \"S\",\n \"DistanceKm\": 382296.46854\n }\n },\n {\n \"Date\": \"2023-03-14\",\n \"IsMoonRise\": true,\n \"IsMoonSet\": true,\n \"IsMeridian\": true,\n \"Moonrise\": {\n \"Time\": 1678739357,\n \"AzimuthDegrees\": 131.64699,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"SE\",\n \"DistanceKm\": 378807.06957\n },\n \"Moonset\": {\n \"Time\": 1678766372,\n \"AzimuthDegrees\": 226.46039,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"SW\",\n \"DistanceKm\": 377554.30425\n },\n \"Meridian\": {\n \"Time\": 1678753085,\n \"AzimuthDegrees\": 180,\n \"AltitudeDegrees\": 13.1,\n \"Direction\": \"S\",\n \"DistanceKm\": 378170.5856\n }\n },\n {\n \"Date\": \"2023-03-15\",\n \"IsMoonRise\": true,\n \"IsMoonSet\": true,\n \"IsMeridian\": true,\n \"Moonrise\": {\n \"Time\": 1678830525,\n \"AzimuthDegrees\": 137.04254,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"SE\",\n \"DistanceKm\": 374594.67251\n },\n \"Moonset\": {\n \"Time\": 1678855238,\n \"AzimuthDegrees\": 222.05405,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"SW\",\n \"DistanceKm\": 373473.15308\n },\n \"Meridian\": {\n \"Time\": 1678842992,\n \"AzimuthDegrees\": 180,\n \"AltitudeDegrees\": 10.7,\n \"Direction\": \"S\",\n \"DistanceKm\": 374026.97617\n }\n },\n {\n \"Date\": \"2023-03-16\",\n \"IsMoonRise\": true,\n \"IsMoonSet\": true,\n \"IsMeridian\": true,\n \"Moonrise\": {\n \"Time\": 1678921072,\n \"AzimuthDegrees\": 138.9114,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"SE\",\n \"DistanceKm\": 370591.50029\n },\n \"Moonset\": {\n \"Time\": 1678945166,\n \"AzimuthDegrees\": 221.29657,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"SW\",\n \"DistanceKm\": 369592.67725\n },\n \"Meridian\": {\n \"Time\": 1678933092,\n \"AzimuthDegrees\": 180,\n \"AltitudeDegrees\": 10.1,\n \"Direction\": \"S\",\n \"DistanceKm\": 370088.60593\n }\n },\n {\n \"Date\": \"2023-03-17\",\n \"IsMoonRise\": true,\n \"IsMoonSet\": true,\n \"IsMeridian\": true,\n \"Moonrise\": {\n \"Time\": 1679010663,\n \"AzimuthDegrees\": 136.61246,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"SE\",\n \"DistanceKm\": 367098.86901\n },\n \"Moonset\": {\n \"Time\": 1679036174,\n \"AzimuthDegrees\": 224.76797,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"SW\",\n \"DistanceKm\": 366237.19817\n },\n \"Meridian\": {\n \"Time\": 1679023251,\n \"AzimuthDegrees\": 180,\n \"AltitudeDegrees\": 11.4,\n \"Direction\": \"S\",\n \"DistanceKm\": 366664.93323\n }\n },\n {\n \"Date\": \"2023-03-18\",\n \"IsMoonRise\": true,\n \"IsMoonSet\": true,\n \"IsMeridian\": true,\n \"Moonrise\": {\n \"Time\": 1679099326,\n \"AzimuthDegrees\": 130.65168,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"SE\",\n \"DistanceKm\": 364441.40172\n },\n \"Moonset\": {\n \"Time\": 1679127890,\n \"AzimuthDegrees\": 231.87919,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"SW\",\n \"DistanceKm\": 363812.28579\n },\n \"Meridian\": {\n \"Time\": 1679113319,\n \"AzimuthDegrees\": 180,\n \"AltitudeDegrees\": 14.8,\n \"Direction\": \"S\",\n \"DistanceKm\": 364117.71582\n }\n },\n {\n \"Date\": \"2023-03-19\",\n \"IsMoonRise\": true,\n \"IsMoonSet\": true,\n \"IsMeridian\": true,\n \"Moonrise\": {\n \"Time\": 1679187320,\n \"AzimuthDegrees\": 122.15123,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"ESE\",\n \"DistanceKm\": 362929.11813\n },\n \"Moonset\": {\n \"Time\": 1679219833,\n \"AzimuthDegrees\": 241.42982,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"WSW\",\n \"DistanceKm\": 362712.81832\n },\n \"Meridian\": {\n \"Time\": 1679203194,\n \"AzimuthDegrees\": 180,\n \"AltitudeDegrees\": 19.7,\n \"Direction\": \"S\",\n \"DistanceKm\": 362798.79835\n }\n },\n {\n \"Date\": \"2023-03-20\",\n \"IsMoonRise\": true,\n \"IsMoonSet\": true,\n \"IsMeridian\": true,\n \"Moonrise\": {\n \"Time\": 1679274902,\n \"AzimuthDegrees\": 112.14362,\n \"AltitudeDegrees\": -0.56666,\n \"Direction\": \"ESE\",\n \"DistanceKm\": 362812.63242\n },\n \"Moonset\": {\n \"Time\": 1679311702,\n \"AzimuthDegrees\": 252.32977,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"WSW\",\n \"DistanceKm\": 363219.08698\n },\n \"Meridian\": {\n \"Time\": 1679292852,\n \"AzimuthDegrees\": 180,\n \"AltitudeDegrees\": 25.9,\n \"Direction\": \"S\",\n \"DistanceKm\": 362976.42916\n }\n },\n {\n \"Date\": \"2023-03-21\",\n \"IsMoonRise\": true,\n \"IsMoonSet\": true,\n \"IsMeridian\": true,\n \"Moonrise\": {\n \"Time\": 1679362254,\n \"AzimuthDegrees\": 101.3864,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"ESE\",\n \"DistanceKm\": 364227.26916\n },\n \"Moonset\": {\n \"Time\": 1679403400,\n \"AzimuthDegrees\": 263.78338,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"W\",\n \"DistanceKm\": 365425.30425\n },\n \"Meridian\": {\n \"Time\": 1679382325,\n \"AzimuthDegrees\": 180,\n \"AltitudeDegrees\": 32.8,\n \"Direction\": \"S\",\n \"DistanceKm\": 364770.21284\n }\n },\n {\n \"Date\": \"2023-03-22\",\n \"IsMoonRise\": true,\n \"IsMoonSet\": true,\n \"IsMeridian\": true,\n \"Moonrise\": {\n \"Time\": 1679449497,\n \"AzimuthDegrees\": 90.43001,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"E\",\n \"DistanceKm\": 367149.18373\n },\n \"Moonset\": {\n \"Time\": 1679494947,\n \"AzimuthDegrees\": 275.21269,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"W\",\n \"DistanceKm\": 369210.60777\n },\n \"Meridian\": {\n \"Time\": 1679471677,\n \"AzimuthDegrees\": 180,\n \"AltitudeDegrees\": 39.9,\n \"Direction\": \"S\",\n \"DistanceKm\": 368112.88854\n }\n },\n {\n \"Date\": \"2023-03-23\",\n \"IsMoonRise\": true,\n \"IsMoonSet\": true,\n \"IsMeridian\": true,\n \"Moonrise\": {\n \"Time\": 1679536722,\n \"AzimuthDegrees\": 79.70263,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"E\",\n \"DistanceKm\": 371383.43121\n },\n \"Moonset\": {\n \"Time\": 1679586398,\n \"AzimuthDegrees\": 286.16029,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"WNW\",\n \"DistanceKm\": 374253.93367\n },\n \"Meridian\": {\n \"Time\": 1679560980,\n \"AzimuthDegrees\": 180,\n \"AltitudeDegrees\": 46.7,\n \"Direction\": \"S\",\n \"DistanceKm\": 372750.53254\n }\n },\n {\n \"Date\": \"2023-03-24\",\n \"IsMoonRise\": true,\n \"IsMoonSet\": true,\n \"IsMeridian\": true,\n \"Moonrise\": {\n \"Time\": 1679624012,\n \"AzimuthDegrees\": 69.57123,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"ENE\",\n \"DistanceKm\": 376588.54488\n },\n \"Moonset\": {\n \"Time\": 1679677785,\n \"AzimuthDegrees\": 296.21187,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"WNW\",\n \"DistanceKm\": 380086.26614\n },\n \"Meridian\": {\n \"Time\": 1679650299,\n \"AzimuthDegrees\": 180,\n \"AltitudeDegrees\": 52.9,\n \"Direction\": \"S\",\n \"DistanceKm\": 378280.3871\n }\n },\n {\n \"Date\": \"2023-03-25\",\n \"IsMoonRise\": true,\n \"IsMoonSet\": true,\n \"IsMeridian\": true,\n \"Moonrise\": {\n \"Time\": 1679711456,\n \"AzimuthDegrees\": 60.39425,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"ENE\",\n \"DistanceKm\": 382327.95573\n },\n \"Moonset\": {\n \"Time\": 1679769074,\n \"AzimuthDegrees\": 304.92579,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"NW\",\n \"DistanceKm\": 386164.32159\n },\n \"Meridian\": {\n \"Time\": 1679739679,\n \"AzimuthDegrees\": 180,\n \"AltitudeDegrees\": 58.2,\n \"Direction\": \"S\",\n \"DistanceKm\": 384213.14123\n }\n },\n {\n \"Date\": \"2023-03-26\",\n \"IsMoonRise\": true,\n \"IsMoonSet\": false,\n \"IsMeridian\": true,\n \"Moonrise\": {\n \"Time\": 1679799169,\n \"AzimuthDegrees\": 52.57818,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"NE\",\n \"DistanceKm\": 388131.21721\n },\n \"Meridian\": {\n \"Time\": 1679829144,\n \"AzimuthDegrees\": 180,\n \"AltitudeDegrees\": 62.3,\n \"Direction\": \"S\",\n \"DistanceKm\": 390041.63582\n }\n },\n {\n \"Date\": \"2023-03-27\",\n \"IsMoonRise\": true,\n \"IsMoonSet\": true,\n \"IsMeridian\": true,\n \"Moonrise\": {\n \"Time\": 1679887300,\n \"AzimuthDegrees\": 46.62563,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"NE\",\n \"DistanceKm\": 393548.92562\n },\n \"Moonset\": {\n \"Time\": 1679860134,\n \"AzimuthDegrees\": 311.77602,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"NW\",\n \"DistanceKm\": 391948.19405\n },\n \"Meridian\": {\n \"Time\": 1679918681,\n \"AzimuthDegrees\": 180,\n \"AltitudeDegrees\": 65,\n \"Direction\": \"S\",\n \"DistanceKm\": 395301.62304\n }\n },\n {\n \"Date\": \"2023-03-28\",\n \"IsMoonRise\": true,\n \"IsMoonSet\": true,\n \"IsMeridian\": true,\n \"Moonrise\": {\n \"Time\": 1679976010,\n \"AzimuthDegrees\": 43.11087,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"NE\",\n \"DistanceKm\": 398191.74953\n },\n \"Moonset\": {\n \"Time\": 1679950741,\n \"AzimuthDegrees\": 316.17036,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"NW\",\n \"DistanceKm\": 396971.11487\n },\n \"Meridian\": {\n \"Time\": 1680008246,\n \"AzimuthDegrees\": 180,\n \"AltitudeDegrees\": 66.3,\n \"Direction\": \"S\",\n \"DistanceKm\": 399617.2651\n }\n },\n {\n \"Date\": \"2023-03-29\",\n \"IsMoonRise\": true,\n \"IsMoonSet\": true,\n \"IsMeridian\": true,\n \"Moonrise\": {\n \"Time\": 1680065405,\n \"AzimuthDegrees\": 42.48507,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"NE\",\n \"DistanceKm\": 401753.75503\n },\n \"Moonset\": {\n \"Time\": 1680040664,\n \"AzimuthDegrees\": 317.64261,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"NW\",\n \"DistanceKm\": 400892.49384\n },\n \"Meridian\": {\n \"Time\": 1680097776,\n \"AzimuthDegrees\": 180,\n \"AltitudeDegrees\": 66.1,\n \"Direction\": \"S\",\n \"DistanceKm\": 402729.21577\n }\n },\n {\n \"Date\": \"2023-03-30\",\n \"IsMoonRise\": true,\n \"IsMoonSet\": true,\n \"IsMeridian\": true,\n \"Moonrise\": {\n \"Time\": 1680155438,\n \"AzimuthDegrees\": 44.77953,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"NE\",\n \"DistanceKm\": 404030.19632\n },\n \"Moonset\": {\n \"Time\": 1680129800,\n \"AzimuthDegrees\": 316.15045,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"NW\",\n \"DistanceKm\": 403521.433\n },\n \"Meridian\": {\n \"Time\": 1680187209,\n \"AzimuthDegrees\": 180,\n \"AltitudeDegrees\": 64.4,\n \"Direction\": \"S\",\n \"DistanceKm\": 404505.37243\n }\n },\n {\n \"Date\": \"2023-03-31\",\n \"IsMoonRise\": true,\n \"IsMoonSet\": true,\n \"IsMeridian\": true,\n \"Moonrise\": {\n \"Time\": 1680245913,\n \"AzimuthDegrees\": 49.55137,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"NE\",\n \"DistanceKm\": 404935.96867\n },\n \"Moonset\": {\n \"Time\": 1680218226,\n \"AzimuthDegrees\": 312.1322,\n \"AltitudeDegrees\": -0.56667,\n \"Direction\": \"NW\",\n \"DistanceKm\": 404804.48186\n },\n \"Meridian\": {\n \"Time\": 1680276504,\n \"AzimuthDegrees\": 180,\n \"AltitudeDegrees\": 61.6,\n \"Direction\": \"S\",\n \"DistanceKm\": 404936.05398\n }\n }\n]" + } + ] + } + ] + }, + { + "name": "Moon Phase — Core information for year (phase)", + "item": [ + { + "name": "Get moon phases table by specified year", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/v1/moonTableYear?utc=5&year=2023&timeFormat=2006-01-02 15:04", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "v1", + "moonTableYear" + ], + "query": [ + { + "key": "utc", + "value": "5", + "description": "Timezone. Example: \"UTC+5\", \"5\", \"-10:30\"" + }, + { + "key": "year", + "value": "2023", + "description": "Year for request: YYYY. Current, if not specified" + }, + { + "key": "timeFormat", + "value": "2006-01-02 15:04", + "description": "Supports: \"ISO\" (default), \"timestamp\" any Go time format directives (without UTC), for example: \"Mon, 02 Jan 2006 15:04:05\"" + } + ] + }, + "description": "Detailed information:\n\n[https://github.com/prostraction/moon?tab=readme-ov-file#get-v1moontableyear](https://github.com/prostraction/moon?tab=readme-ov-file#get-v1moontableyear)\n\nThe method returns the moon phases for the given year. The response contains an array for each month, each element of which contains the time of the new moon, first quarter, full moon, last quarter." + }, + "response": [ + { + "name": "moonTableYear", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/v1/moonTableYear?utc=5&year=2025", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "v1", + "moonTableYear" + ], + "query": [ + { + "key": "utc", + "value": "5", + "description": "Timezone. Example: \"UTC+5\", \"5\", \"-10:30\"" + }, + { + "key": "year", + "value": "2025", + "description": "Year for request: YYYY. Current, if not specified" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Server", + "value": "nginx/1.24.0 (Ubuntu)" + }, + { + "key": "Date", + "value": "Tue, 04 Nov 2025 11:31:11 GMT" + }, + { + "key": "Content-Type", + "value": "application/json", + "description": "", + "type": "text" + }, + { + "key": "Content-Length", + "value": "2133" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Keep-Alive", + "value": "timeout=900" + } + ], + "cookie": [], + "body": "[\n {\n \"NewMoon\": \"2024-12-31T03:27:49+05:00\",\n \"FirstQuarter\": \"2025-01-07T04:34:13+05:00\",\n \"FullMoon\": \"2025-01-14T03:27:44+05:00\",\n \"LastQuarter\": \"2025-01-22T01:42:58+05:00\"\n },\n {\n \"NewMoon\": \"2025-01-29T17:37:18+05:00\",\n \"FirstQuarter\": \"2025-02-05T12:39:54+05:00\",\n \"FullMoon\": \"2025-02-12T18:54:26+05:00\",\n \"LastQuarter\": \"2025-02-20T22:54:12+05:00\"\n },\n {\n \"NewMoon\": \"2025-02-28T05:46:43+05:00\",\n \"FirstQuarter\": \"2025-03-06T21:17:10+05:00\",\n \"FullMoon\": \"2025-03-14T11:55:56+05:00\",\n \"LastQuarter\": \"2025-03-22T17:09:32+05:00\"\n },\n {\n \"NewMoon\": \"2025-03-29T16:00:07+05:00\",\n \"FirstQuarter\": \"2025-04-05T07:05:24+05:00\",\n \"FullMoon\": \"2025-04-13T05:23:56+05:00\",\n \"LastQuarter\": \"2025-04-21T07:24:10+05:00\"\n },\n {\n \"NewMoon\": \"2025-04-28T00:33:22+05:00\",\n \"FirstQuarter\": \"2025-05-04T18:40:59+05:00\",\n \"FullMoon\": \"2025-05-12T21:58:06+05:00\",\n \"LastQuarter\": \"2025-05-20T17:38:39+05:00\"\n },\n {\n \"NewMoon\": \"2025-05-27T08:04:25+05:00\",\n \"FirstQuarter\": \"2025-06-03T08:18:31+05:00\",\n \"FullMoon\": \"2025-06-11T12:46:06+05:00\",\n \"LastQuarter\": \"2025-06-19T00:39:04+05:00\"\n },\n {\n \"NewMoon\": \"2025-06-25T15:33:30+05:00\",\n \"FirstQuarter\": \"2025-07-02T23:55:45+05:00\",\n \"FullMoon\": \"2025-07-11T01:38:54+05:00\",\n \"LastQuarter\": \"2025-07-18T05:42:32+05:00\"\n },\n {\n \"NewMoon\": \"2025-07-25T00:12:27+05:00\",\n \"FirstQuarter\": \"2025-08-01T17:07:25+05:00\",\n \"FullMoon\": \"2025-08-09T12:57:07+05:00\",\n \"LastQuarter\": \"2025-08-16T10:14:41+05:00\"\n },\n {\n \"NewMoon\": \"2025-08-23T11:07:06+05:00\",\n \"FirstQuarter\": \"2025-08-31T11:05:52+05:00\",\n \"FullMoon\": \"2025-09-07T23:10:41+05:00\",\n \"LastQuarter\": \"2025-09-14T15:47:01+05:00\"\n },\n {\n \"NewMoon\": \"2025-09-22T00:54:36+05:00\",\n \"FirstQuarter\": \"2025-09-30T04:51:14+05:00\",\n \"FullMoon\": \"2025-10-07T08:48:57+05:00\",\n \"LastQuarter\": \"2025-10-13T23:39:48+05:00\"\n },\n {\n \"NewMoon\": \"2025-10-21T17:25:58+05:00\",\n \"FirstQuarter\": \"2025-10-29T21:21:02+05:00\",\n \"FullMoon\": \"2025-11-05T18:20:26+05:00\",\n \"LastQuarter\": \"2025-11-12T10:55:00+05:00\"\n },\n {\n \"NewMoon\": \"2025-11-20T11:48:16+05:00\",\n \"FirstQuarter\": \"2025-11-28T11:44:00+05:00\",\n \"FullMoon\": \"2025-12-05T04:15:18+05:00\",\n \"LastQuarter\": \"2025-12-12T02:04:31+05:00\"\n },\n {\n \"NewMoon\": \"2025-12-20T06:44:25+05:00\",\n \"FirstQuarter\": \"2025-12-27T23:35:58+05:00\",\n \"FullMoon\": \"2026-01-03T15:04:15+05:00\",\n \"LastQuarter\": \"2026-01-10T20:51:36+05:00\"\n }\n]" + }, + { + "name": "moonTableYear — custom timeFormat", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/v1/moonTableYear?utc=5&year=2023&timeFormat=2006-01-02 15:04", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "v1", + "moonTableYear" + ], + "query": [ + { + "key": "utc", + "value": "5", + "description": "Timezone. Example: \"UTC+5\", \"5\", \"-10:30\"" + }, + { + "key": "year", + "value": "2023", + "description": "Year for request: YYYY. Current, if not specified" + }, + { + "key": "timeFormat", + "value": "2006-01-02 15:04", + "description": "Supports: \"ISO\" (default), \"timestamp\" any Go time format directives (without UTC), for example: \"Mon, 02 Jan 2006 15:04:05\"" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "Text", + "header": [ + { + "key": "Server", + "value": "Fiber" + }, + { + "key": "Date", + "value": "Sun, 16 Nov 2025 18:36:08 GMT" + }, + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Content-Length", + "value": "1665" + } + ], + "cookie": [], + "body": "[\n {\n \"NewMoon\": \"2022-12-23 15:17\",\n \"FirstQuarter\": \"2022-12-30 06:24\",\n \"FullMoon\": \"2023-01-07 04:09\",\n \"LastQuarter\": \"2023-01-07 04:09\"\n },\n {\n \"NewMoon\": \"2023-01-22 01:55\",\n \"FirstQuarter\": \"2023-01-28 20:05\",\n \"FullMoon\": \"2023-02-05 23:30\",\n \"LastQuarter\": \"2023-02-05 23:30\"\n },\n {\n \"NewMoon\": \"2023-02-20 12:09\",\n \"FirstQuarter\": \"2023-02-27 12:36\",\n \"FullMoon\": \"2023-03-07 17:42\",\n \"LastQuarter\": \"2023-03-07 17:42\"\n },\n {\n \"NewMoon\": \"2023-03-21 22:26\",\n \"FirstQuarter\": \"2023-03-29 07:03\",\n \"FullMoon\": \"2023-04-06 09:37\",\n \"LastQuarter\": \"2023-04-06 09:37\"\n },\n {\n \"NewMoon\": \"2023-04-20 09:15\",\n \"FirstQuarter\": \"2023-04-28 02:12\",\n \"FullMoon\": \"2023-05-05 22:36\",\n \"LastQuarter\": \"2023-05-05 22:36\"\n },\n {\n \"NewMoon\": \"2023-05-19 20:55\",\n \"FirstQuarter\": \"2023-05-27 20:30\",\n \"FullMoon\": \"2023-06-04 08:43\",\n \"LastQuarter\": \"2023-06-04 08:43\"\n },\n {\n \"NewMoon\": \"2023-06-18 09:39\",\n \"FirstQuarter\": \"2023-06-26 12:59\",\n \"FullMoon\": \"2023-07-03 16:40\",\n \"LastQuarter\": \"2023-07-03 16:40\"\n },\n {\n \"NewMoon\": \"2023-07-17 23:33\",\n \"FirstQuarter\": \"2023-07-26 03:01\",\n \"FullMoon\": \"2023-08-01 23:33\",\n \"LastQuarter\": \"2023-08-01 23:33\"\n },\n {\n \"NewMoon\": \"2023-08-16 14:38\",\n \"FirstQuarter\": \"2023-08-24 14:34\",\n \"FullMoon\": \"2023-08-31 06:37\",\n \"LastQuarter\": \"2023-08-31 06:37\"\n },\n {\n \"NewMoon\": \"2023-09-15 06:40\",\n \"FirstQuarter\": \"2023-09-23 00:03\",\n \"FullMoon\": \"2023-09-29 14:58\",\n \"LastQuarter\": \"2023-09-29 14:58\"\n },\n {\n \"NewMoon\": \"2023-10-14 22:55\",\n \"FirstQuarter\": \"2023-10-22 08:10\",\n \"FullMoon\": \"2023-10-29 01:24\",\n \"LastQuarter\": \"2023-10-29 01:24\"\n },\n {\n \"NewMoon\": \"2023-11-13 14:27\",\n \"FirstQuarter\": \"2023-11-20 15:45\",\n \"FullMoon\": \"2023-11-27 14:16\",\n \"LastQuarter\": \"2023-11-27 14:16\"\n },\n {\n \"NewMoon\": \"2023-12-13 04:32\",\n \"FirstQuarter\": \"2023-12-19 23:42\",\n \"FullMoon\": \"2023-12-27 05:33\",\n \"LastQuarter\": \"2023-12-27 05:33\"\n }\n]" + }, + { + "name": "moonTableYear — timestamp timeFormat", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/v1/moonTableYear?utc=5&year=2023&timeFormat=timestamp", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "v1", + "moonTableYear" + ], + "query": [ + { + "key": "utc", + "value": "5", + "description": "Timezone. Example: \"UTC+5\", \"5\", \"-10:30\"" + }, + { + "key": "year", + "value": "2023", + "description": "Year for request: YYYY. Current, if not specified" + }, + { + "key": "timeFormat", + "value": "timestamp", + "description": "Supports: \"ISO\" (default), \"timestamp\" any Go time format directives (without UTC), for example: \"Mon, 02 Jan 2006 15:04:05\"" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "Text", + "header": [ + { + "key": "Server", + "value": "Fiber" + }, + { + "key": "Date", + "value": "Sun, 16 Nov 2025 18:36:46 GMT" + }, + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Content-Length", + "value": "1249" + } + ], + "cookie": [], + "body": "[\n {\n \"NewMoon\": 1671790676,\n \"FirstQuarter\": 1672363444,\n \"FullMoon\": 1673046595,\n \"LastQuarter\": 1673046595\n },\n {\n \"NewMoon\": 1674334530,\n \"FirstQuarter\": 1674918315,\n \"FullMoon\": 1675621844,\n \"LastQuarter\": 1675621844\n },\n {\n \"NewMoon\": 1676876945,\n \"FirstQuarter\": 1677483389,\n \"FullMoon\": 1678192969,\n \"LastQuarter\": 1678192969\n },\n {\n \"NewMoon\": 1679419604,\n \"FirstQuarter\": 1680055425,\n \"FullMoon\": 1680755838,\n \"LastQuarter\": 1680755838\n },\n {\n \"NewMoon\": 1681964148,\n \"FirstQuarter\": 1682629943,\n \"FullMoon\": 1683308207,\n \"LastQuarter\": 1683308207\n },\n {\n \"NewMoon\": 1684511756,\n \"FirstQuarter\": 1685201420,\n \"FullMoon\": 1685850236,\n \"LastQuarter\": 1685850236\n },\n {\n \"NewMoon\": 1687063150,\n \"FirstQuarter\": 1687766370,\n \"FullMoon\": 1688384430,\n \"LastQuarter\": 1688384430\n },\n {\n \"NewMoon\": 1689618786,\n \"FirstQuarter\": 1690322484,\n \"FullMoon\": 1690914806,\n \"LastQuarter\": 1690914806\n },\n {\n \"NewMoon\": 1692178729,\n \"FirstQuarter\": 1692869661,\n \"FullMoon\": 1693445825,\n \"LastQuarter\": 1693445825\n },\n {\n \"NewMoon\": 1694742005,\n \"FirstQuarter\": 1695409414,\n \"FullMoon\": 1695981501,\n \"LastQuarter\": 1695981501\n },\n {\n \"NewMoon\": 1697306108,\n \"FirstQuarter\": 1697944245,\n \"FullMoon\": 1698524667,\n \"LastQuarter\": 1698524667\n },\n {\n \"NewMoon\": 1699867635,\n \"FirstQuarter\": 1700477136,\n \"FullMoon\": 1701076601,\n \"LastQuarter\": 1701076601\n },\n {\n \"NewMoon\": 1702423927,\n \"FirstQuarter\": 1703011321,\n \"FullMoon\": 1703637223,\n \"LastQuarter\": 1703637223\n }\n]" + } + ] + }, + { + "name": "Get moon phases table by current year", + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "method": "GET", + "header": [], + "body": { + "mode": "raw", + "raw": "", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{baseUrl}}/v1/moonTableCurrent?utc=5&timeFormat=2006-01-02 15:04", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "v1", + "moonTableCurrent" + ], + "query": [ + { + "key": "utc", + "value": "5", + "description": "Timezone. Example: \"UTC+5\", \"5\", \"-10:30\"" + }, + { + "key": "timeFormat", + "value": "2006-01-02 15:04", + "description": "Supports: \"ISO\" (default), \"timestamp\" any Go time format directives (without UTC), for example: \"Mon, 02 Jan 2006 15:04:05\"" + } + ] + }, + "description": "Detailed information:\n\n[https://github.com/prostraction/moon?tab=readme-ov-file#get-v1moontableyear](https://github.com/prostraction/moon?tab=readme-ov-file#get-v1moontableyear)\n\nThe method returns the moon phases for the given year. The response contains an array for each month, each element of which contains the time of the new moon, first quarter, full moon, last quarter." + }, + "response": [ + { + "name": "moonTableCurrent", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/v1/moonTableCurrent?utc=5", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "v1", + "moonTableCurrent" + ], + "query": [ + { + "key": "utc", + "value": "5", + "description": "Timezone. Example: \"UTC+5\", \"5\", \"-10:30\"" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Server", + "value": "nginx/1.24.0 (Ubuntu)" + }, + { + "key": "Date", + "value": "Tue, 04 Nov 2025 11:31:58 GMT" + }, + { + "key": "Content-Type", + "value": "application/json", + "description": "", + "type": "text" + }, + { + "key": "Content-Length", + "value": "2133" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Keep-Alive", + "value": "timeout=900" + } + ], + "cookie": [], + "body": "[\n {\n \"NewMoon\": \"2024-12-31T03:27:49+05:00\",\n \"FirstQuarter\": \"2025-01-07T04:34:13+05:00\",\n \"FullMoon\": \"2025-01-14T03:27:44+05:00\",\n \"LastQuarter\": \"2025-01-22T01:42:58+05:00\"\n },\n {\n \"NewMoon\": \"2025-01-29T17:37:18+05:00\",\n \"FirstQuarter\": \"2025-02-05T12:39:54+05:00\",\n \"FullMoon\": \"2025-02-12T18:54:26+05:00\",\n \"LastQuarter\": \"2025-02-20T22:54:12+05:00\"\n },\n {\n \"NewMoon\": \"2025-02-28T05:46:43+05:00\",\n \"FirstQuarter\": \"2025-03-06T21:17:10+05:00\",\n \"FullMoon\": \"2025-03-14T11:55:56+05:00\",\n \"LastQuarter\": \"2025-03-22T17:09:32+05:00\"\n },\n {\n \"NewMoon\": \"2025-03-29T16:00:07+05:00\",\n \"FirstQuarter\": \"2025-04-05T07:05:24+05:00\",\n \"FullMoon\": \"2025-04-13T05:23:56+05:00\",\n \"LastQuarter\": \"2025-04-21T07:24:10+05:00\"\n },\n {\n \"NewMoon\": \"2025-04-28T00:33:22+05:00\",\n \"FirstQuarter\": \"2025-05-04T18:40:59+05:00\",\n \"FullMoon\": \"2025-05-12T21:58:06+05:00\",\n \"LastQuarter\": \"2025-05-20T17:38:39+05:00\"\n },\n {\n \"NewMoon\": \"2025-05-27T08:04:25+05:00\",\n \"FirstQuarter\": \"2025-06-03T08:18:31+05:00\",\n \"FullMoon\": \"2025-06-11T12:46:06+05:00\",\n \"LastQuarter\": \"2025-06-19T00:39:04+05:00\"\n },\n {\n \"NewMoon\": \"2025-06-25T15:33:30+05:00\",\n \"FirstQuarter\": \"2025-07-02T23:55:45+05:00\",\n \"FullMoon\": \"2025-07-11T01:38:54+05:00\",\n \"LastQuarter\": \"2025-07-18T05:42:32+05:00\"\n },\n {\n \"NewMoon\": \"2025-07-25T00:12:27+05:00\",\n \"FirstQuarter\": \"2025-08-01T17:07:25+05:00\",\n \"FullMoon\": \"2025-08-09T12:57:07+05:00\",\n \"LastQuarter\": \"2025-08-16T10:14:41+05:00\"\n },\n {\n \"NewMoon\": \"2025-08-23T11:07:06+05:00\",\n \"FirstQuarter\": \"2025-08-31T11:05:52+05:00\",\n \"FullMoon\": \"2025-09-07T23:10:41+05:00\",\n \"LastQuarter\": \"2025-09-14T15:47:01+05:00\"\n },\n {\n \"NewMoon\": \"2025-09-22T00:54:36+05:00\",\n \"FirstQuarter\": \"2025-09-30T04:51:14+05:00\",\n \"FullMoon\": \"2025-10-07T08:48:57+05:00\",\n \"LastQuarter\": \"2025-10-13T23:39:48+05:00\"\n },\n {\n \"NewMoon\": \"2025-10-21T17:25:58+05:00\",\n \"FirstQuarter\": \"2025-10-29T21:21:02+05:00\",\n \"FullMoon\": \"2025-11-05T18:20:26+05:00\",\n \"LastQuarter\": \"2025-11-12T10:55:00+05:00\"\n },\n {\n \"NewMoon\": \"2025-11-20T11:48:16+05:00\",\n \"FirstQuarter\": \"2025-11-28T11:44:00+05:00\",\n \"FullMoon\": \"2025-12-05T04:15:18+05:00\",\n \"LastQuarter\": \"2025-12-12T02:04:31+05:00\"\n },\n {\n \"NewMoon\": \"2025-12-20T06:44:25+05:00\",\n \"FirstQuarter\": \"2025-12-27T23:35:58+05:00\",\n \"FullMoon\": \"2026-01-03T15:04:15+05:00\",\n \"LastQuarter\": \"2026-01-10T20:51:36+05:00\"\n }\n]" + }, + { + "name": "moonTableCurrent — custom timeFormat", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/v1/moonTableCurrent?utc=5&timeFormat=2006-01-02 15:04", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "v1", + "moonTableCurrent" + ], + "query": [ + { + "key": "utc", + "value": "5", + "description": "Timezone. Example: \"UTC+5\", \"5\", \"-10:30\"" + }, + { + "key": "timeFormat", + "value": "2006-01-02 15:04", + "description": "Supports: \"ISO\" (default), \"timestamp\" any Go time format directives (without UTC), for example: \"Mon, 02 Jan 2006 15:04:05\"" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "Text", + "header": [ + { + "key": "Server", + "value": "Fiber" + }, + { + "key": "Date", + "value": "Sun, 16 Nov 2025 18:37:44 GMT" + }, + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Content-Length", + "value": "1665" + } + ], + "cookie": [], + "body": "[\n {\n \"NewMoon\": \"2024-12-31 03:27\",\n \"FirstQuarter\": \"2025-01-07 04:34\",\n \"FullMoon\": \"2025-01-14 03:27\",\n \"LastQuarter\": \"2025-01-14 03:27\"\n },\n {\n \"NewMoon\": \"2025-01-29 17:37\",\n \"FirstQuarter\": \"2025-02-05 12:39\",\n \"FullMoon\": \"2025-02-12 18:54\",\n \"LastQuarter\": \"2025-02-12 18:54\"\n },\n {\n \"NewMoon\": \"2025-02-28 05:46\",\n \"FirstQuarter\": \"2025-03-06 21:17\",\n \"FullMoon\": \"2025-03-14 11:55\",\n \"LastQuarter\": \"2025-03-14 11:55\"\n },\n {\n \"NewMoon\": \"2025-03-29 16:00\",\n \"FirstQuarter\": \"2025-04-05 07:05\",\n \"FullMoon\": \"2025-04-13 05:23\",\n \"LastQuarter\": \"2025-04-13 05:23\"\n },\n {\n \"NewMoon\": \"2025-04-28 00:33\",\n \"FirstQuarter\": \"2025-05-04 18:40\",\n \"FullMoon\": \"2025-05-12 21:58\",\n \"LastQuarter\": \"2025-05-12 21:58\"\n },\n {\n \"NewMoon\": \"2025-05-27 08:04\",\n \"FirstQuarter\": \"2025-06-03 08:18\",\n \"FullMoon\": \"2025-06-11 12:46\",\n \"LastQuarter\": \"2025-06-11 12:46\"\n },\n {\n \"NewMoon\": \"2025-06-25 15:33\",\n \"FirstQuarter\": \"2025-07-02 23:55\",\n \"FullMoon\": \"2025-07-11 01:38\",\n \"LastQuarter\": \"2025-07-11 01:38\"\n },\n {\n \"NewMoon\": \"2025-07-25 00:12\",\n \"FirstQuarter\": \"2025-08-01 17:07\",\n \"FullMoon\": \"2025-08-09 12:57\",\n \"LastQuarter\": \"2025-08-09 12:57\"\n },\n {\n \"NewMoon\": \"2025-08-23 11:07\",\n \"FirstQuarter\": \"2025-08-31 11:05\",\n \"FullMoon\": \"2025-09-07 23:10\",\n \"LastQuarter\": \"2025-09-07 23:10\"\n },\n {\n \"NewMoon\": \"2025-09-22 00:54\",\n \"FirstQuarter\": \"2025-09-30 04:51\",\n \"FullMoon\": \"2025-10-07 08:48\",\n \"LastQuarter\": \"2025-10-07 08:48\"\n },\n {\n \"NewMoon\": \"2025-10-21 17:25\",\n \"FirstQuarter\": \"2025-10-29 21:21\",\n \"FullMoon\": \"2025-11-05 18:20\",\n \"LastQuarter\": \"2025-11-05 18:20\"\n },\n {\n \"NewMoon\": \"2025-11-20 11:48\",\n \"FirstQuarter\": \"2025-11-28 11:44\",\n \"FullMoon\": \"2025-12-05 04:15\",\n \"LastQuarter\": \"2025-12-05 04:15\"\n },\n {\n \"NewMoon\": \"2025-12-20 06:44\",\n \"FirstQuarter\": \"2025-12-27 23:35\",\n \"FullMoon\": \"2026-01-03 15:04\",\n \"LastQuarter\": \"2026-01-03 15:04\"\n }\n]" + }, + { + "name": "moonTableCurrent — timestamp timeFormat", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/v1/moonTableCurrent?utc=5&timeFormat=timestamp", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "v1", + "moonTableCurrent" + ], + "query": [ + { + "key": "utc", + "value": "5", + "description": "Timezone. Example: \"UTC+5\", \"5\", \"-10:30\"" + }, + { + "key": "timeFormat", + "value": "timestamp", + "description": "Supports: \"ISO\" (default), \"timestamp\" any Go time format directives (without UTC), for example: \"Mon, 02 Jan 2006 15:04:05\"" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "Text", + "header": [ + { + "key": "Server", + "value": "Fiber" + }, + { + "key": "Date", + "value": "Sun, 16 Nov 2025 18:38:09 GMT" + }, + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Content-Length", + "value": "1249" + } + ], + "cookie": [], + "body": "[\n {\n \"NewMoon\": 1735597669,\n \"FirstQuarter\": 1736206453,\n \"FullMoon\": 1736807264,\n \"LastQuarter\": 1736807264\n },\n {\n \"NewMoon\": 1738154238,\n \"FirstQuarter\": 1738741194,\n \"FullMoon\": 1739368466,\n \"LastQuarter\": 1739368466\n },\n {\n \"NewMoon\": 1740703603,\n \"FirstQuarter\": 1741277830,\n \"FullMoon\": 1741935356,\n \"LastQuarter\": 1741935356\n },\n {\n \"NewMoon\": 1743246007,\n \"FirstQuarter\": 1743818724,\n \"FullMoon\": 1744503836,\n \"LastQuarter\": 1744503836\n },\n {\n \"NewMoon\": 1745782402,\n \"FirstQuarter\": 1746366059,\n \"FullMoon\": 1747069086,\n \"LastQuarter\": 1747069086\n },\n {\n \"NewMoon\": 1748315065,\n \"FirstQuarter\": 1748920711,\n \"FullMoon\": 1749627966,\n \"LastQuarter\": 1749627966\n },\n {\n \"NewMoon\": 1750847610,\n \"FirstQuarter\": 1751482545,\n \"FullMoon\": 1752179934,\n \"LastQuarter\": 1752179934\n },\n {\n \"NewMoon\": 1753384347,\n \"FirstQuarter\": 1754050045,\n \"FullMoon\": 1754726227,\n \"LastQuarter\": 1754726227\n },\n {\n \"NewMoon\": 1755929226,\n \"FirstQuarter\": 1756620352,\n \"FullMoon\": 1757268641,\n \"LastQuarter\": 1757268641\n },\n {\n \"NewMoon\": 1758484476,\n \"FirstQuarter\": 1759189874,\n \"FullMoon\": 1759808937,\n \"LastQuarter\": 1759808937\n },\n {\n \"NewMoon\": 1761049558,\n \"FirstQuarter\": 1761754862,\n \"FullMoon\": 1762348826,\n \"LastQuarter\": 1762348826\n },\n {\n \"NewMoon\": 1763621296,\n \"FirstQuarter\": 1764312240,\n \"FullMoon\": 1764890118,\n \"LastQuarter\": 1764890118\n },\n {\n \"NewMoon\": 1766195065,\n \"FirstQuarter\": 1766860558,\n \"FullMoon\": 1767434655,\n \"LastQuarter\": 1767434655\n }\n]" + } + ] + } + ] + }, + { + "name": "Julian Time", + "item": [ + { + "name": "Get Julian Time by specified/current date", + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "method": "GET", + "header": [], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "{{baseUrl}}/v1/toJulianTimeByDate?precision=5&year=2025&month=01&day=01&hour=01&minute=01&second=01&timeFormat=02 Jan 2006 15:04:05", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "v1", + "toJulianTimeByDate" + ], + "query": [ + { + "key": "precision", + "value": "5", + "description": "How many digits after . will be in output. Allowed range: [1, 20]" + }, + { + "key": "year", + "value": "2025", + "description": "Format: YYYY Allowed range: [1, 9999]. Current, if not specified" + }, + { + "key": "month", + "value": "01", + "description": "Format: M or MM. Allowed range: [1, 12]. Current, if not specified" + }, + { + "key": "day", + "value": "01", + "description": "Format: D or DD. Allowed range: [1, 31]. Current, if not specified" + }, + { + "key": "hour", + "value": "01", + "description": "Format: h or hh. Allowed range: [0, 23]. Current, if not specified" + }, + { + "key": "minute", + "value": "01", + "description": "Format: m or mm. Allowed range: [0, 59] Current, if not specified" + }, + { + "key": "second", + "value": "01", + "description": "Format: s or ss. Allowed range: [0, 59]. Current, if not specified" + }, + { + "key": "timeFormat", + "value": "02 Jan 2006 15:04:05", + "description": "Supports: \"ISO\" (default), \"timestamp\" any Go time format directives (without UTC), for example: \"Mon, 02 Jan 2006 15:04:05\"" + } + ] + } + }, + "response": [ + { + "name": "toJulianTimeByDate", + "originalRequest": { + "method": "GET", + "header": [], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "{{baseUrl}}/v1/toJulianTimeByDate?precision=5&year=2025&month=01&day=01&hour=01&minute=01&second=01&timeFormat=ISO", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "v1", + "toJulianTimeByDate" + ], + "query": [ + { + "key": "precision", + "value": "5", + "description": "How many digits after . will be in output. Allowed range: [1, 20]" + }, + { + "key": "year", + "value": "2025", + "description": "Format: YYYY Allowed range: [1, 9999]. Current, if not specified" + }, + { + "key": "month", + "value": "01", + "description": "Format: M or MM. Allowed range: [1, 12]. Current, if not specified" + }, + { + "key": "day", + "value": "01", + "description": "Format: D or DD. Allowed range: [1, 31]. Current, if not specified" + }, + { + "key": "hour", + "value": "01", + "description": "Format: h or hh. Allowed range: [0, 23]. Current, if not specified" + }, + { + "key": "minute", + "value": "01", + "description": "Format: m or mm. Allowed range: [0, 59] Current, if not specified" + }, + { + "key": "second", + "value": "01", + "description": "Format: s or ss. Allowed range: [0, 59]. Current, if not specified" + }, + { + "key": "timeFormat", + "value": "ISO", + "description": "Supports: \"ISO\" (default), \"timestamp\" any Go time format directives (without UTC), for example: \"Mon, 02 Jan 2006 15:04:05\"" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": null, + "header": [ + { + "key": "Server", + "value": "Fiber" + }, + { + "key": "Date", + "value": "Mon, 17 Nov 2025 04:26:30 GMT" + }, + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Content-Length", + "value": "63" + } + ], + "cookie": [], + "body": "{\n \"CivilDate\": \"2025-01-01T01:01:01Z\",\n \"JulianDate\": 2460676.54237\n}" + }, + { + "name": "toJulianTimeByDate — custom timeFormat", + "originalRequest": { + "method": "GET", + "header": [], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "{{baseUrl}}/v1/toJulianTimeByDate?precision=5&year=2025&month=01&day=01&hour=01&minute=01&second=01&timeFormat=Mon, 02 Jan 2006 15:04:05", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "v1", + "toJulianTimeByDate" + ], + "query": [ + { + "key": "precision", + "value": "5", + "description": "How many digits after . will be in output. Allowed range: [1, 20]" + }, + { + "key": "year", + "value": "2025", + "description": "Format: YYYY Allowed range: [1, 9999]. Current, if not specified" + }, + { + "key": "month", + "value": "01", + "description": "Format: M or MM. Allowed range: [1, 12]. Current, if not specified" + }, + { + "key": "day", + "value": "01", + "description": "Format: D or DD. Allowed range: [1, 31]. Current, if not specified" + }, + { + "key": "hour", + "value": "01", + "description": "Format: h or hh. Allowed range: [0, 23]. Current, if not specified" + }, + { + "key": "minute", + "value": "01", + "description": "Format: m or mm. Allowed range: [0, 59] Current, if not specified" + }, + { + "key": "second", + "value": "01", + "description": "Format: s or ss. Allowed range: [0, 59]. Current, if not specified" + }, + { + "key": "timeFormat", + "value": "Mon, 02 Jan 2006 15:04:05", + "description": "Supports: \"ISO\" (default), \"timestamp\" any Go time format directives (without UTC), for example: \"Mon, 02 Jan 2006 15:04:05\"" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Server", + "value": "Fiber" + }, + { + "key": "Date", + "value": "Mon, 17 Nov 2025 04:23:36 GMT" + }, + { + "key": "Content-Type", + "value": "application/json", + "name": "Content-Type", + "description": "", + "type": "text" + }, + { + "key": "Content-Length", + "value": "68" + } + ], + "cookie": [], + "body": "{\n \"CivilDate\": \"Wed, 01 Jan 2025 01:01:01\",\n \"JulianDate\": 2460676.54237\n}" + }, + { + "name": "toJulianTimeByDate — timestamp timeFormat", + "originalRequest": { + "method": "GET", + "header": [], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "{{baseUrl}}/v1/toJulianTimeByDate?precision=5&year=2025&month=01&day=01&hour=01&minute=01&second=01&timeFormat=timestamp", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "v1", + "toJulianTimeByDate" + ], + "query": [ + { + "key": "precision", + "value": "5", + "description": "How many digits after . will be in output. Allowed range: [1, 20]" + }, + { + "key": "year", + "value": "2025", + "description": "Format: YYYY Allowed range: [1, 9999]. Current, if not specified" + }, + { + "key": "month", + "value": "01", + "description": "Format: M or MM. Allowed range: [1, 12]. Current, if not specified" + }, + { + "key": "day", + "value": "01", + "description": "Format: D or DD. Allowed range: [1, 31]. Current, if not specified" + }, + { + "key": "hour", + "value": "01", + "description": "Format: h or hh. Allowed range: [0, 23]. Current, if not specified" + }, + { + "key": "minute", + "value": "01", + "description": "Format: m or mm. Allowed range: [0, 59] Current, if not specified" + }, + { + "key": "second", + "value": "01", + "description": "Format: s or ss. Allowed range: [0, 59]. Current, if not specified" + }, + { + "key": "timeFormat", + "value": "timestamp", + "description": "Supports: \"ISO\" (default), \"timestamp\" any Go time format directives (without UTC), for example: \"Mon, 02 Jan 2006 15:04:05\"" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Server", + "value": "Fiber" + }, + { + "key": "Date", + "value": "Mon, 17 Nov 2025 04:24:35 GMT" + }, + { + "key": "Content-Type", + "value": "application/json", + "name": "Content-Type", + "description": "", + "type": "text" + }, + { + "key": "Content-Length", + "value": "51" + } + ], + "cookie": [], + "body": "{\n \"CivilDate\": 1735693261,\n \"JulianDate\": 2460676.54237\n}" + } + ] + }, + { + "name": "Get Julian Time by timestamp", + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "method": "GET", + "header": [], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "{{baseUrl}}/v1/toJulianTimeByTimestamp?precision=10×tamp=1735693261&timeFormat=Mon, 02 Jan 2006 15:04:05", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "v1", + "toJulianTimeByTimestamp" + ], + "query": [ + { + "key": "precision", + "value": "10", + "description": "How many digits after . will be in output. Allowed range: [1, 20]" + }, + { + "key": "timestamp", + "value": "1735693261", + "description": "Timestamp for calculations. Current, if not specified" + }, + { + "key": "timeFormat", + "value": "Mon, 02 Jan 2006 15:04:05", + "description": "Supports: \"ISO\" (default), \"timestamp\" any Go time format directives (without UTC), for example: \"Mon, 02 Jan 2006 15:04:05\"" + } + ] + } + }, + "response": [ + { + "name": "toJulianTimeByTimestamp", + "originalRequest": { + "method": "GET", + "header": [], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "{{baseUrl}}/v1/toJulianTimeByTimestamp?precision=10×tamp=1735693261", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "v1", + "toJulianTimeByTimestamp" + ], + "query": [ + { + "key": "precision", + "value": "10", + "description": "How many digits after . will be in output. Allowed range: [1, 20]" + }, + { + "key": "timestamp", + "value": "1735693261", + "description": "Timestamp for calculations. Current, if not specified" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Server", + "value": "Fiber" + }, + { + "key": "Date", + "value": "Mon, 17 Nov 2025 04:26:15 GMT" + }, + { + "key": "Content-Type", + "value": "application/json", + "name": "Content-Type", + "description": "", + "type": "text" + }, + { + "key": "Content-Length", + "value": "68" + } + ], + "cookie": [], + "body": "{\n \"CivilDate\": \"2025-01-01T01:01:01Z\",\n \"JulianDate\": 2460676.5423726854\n}" + }, + { + "name": "toJulianTimeByTimestamp — custom timeFormat", + "originalRequest": { + "method": "GET", + "header": [], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "{{baseUrl}}/v1/toJulianTimeByTimestamp?precision=10×tamp=1735693261&timeFormat=Mon, 02 Jan 2006 15:04:05", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "v1", + "toJulianTimeByTimestamp" + ], + "query": [ + { + "key": "precision", + "value": "10", + "description": "How many digits after . will be in output. Allowed range: [1, 20]" + }, + { + "key": "timestamp", + "value": "1735693261", + "description": "Timestamp for calculations. Current, if not specified" + }, + { + "key": "timeFormat", + "value": "Mon, 02 Jan 2006 15:04:05", + "description": "Supports: \"ISO\" (default), \"timestamp\" any Go time format directives (without UTC), for example: \"Mon, 02 Jan 2006 15:04:05\"" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Server", + "value": "Fiber" + }, + { + "key": "Date", + "value": "Mon, 17 Nov 2025 04:27:18 GMT" + }, + { + "key": "Content-Type", + "value": "application/json", + "name": "Content-Type", + "description": "", + "type": "text" + }, + { + "key": "Content-Length", + "value": "73" + } + ], + "cookie": [], + "body": "{\n \"CivilDate\": \"Wed, 01 Jan 2025 01:01:01\",\n \"JulianDate\": 2460676.5423726854\n}" + }, + { + "name": "toJulianTimeByTimestamp — timestamp timeFormat", + "originalRequest": { + "method": "GET", + "header": [], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "{{baseUrl}}/v1/toJulianTimeByTimestamp?precision=10×tamp=1735693261&timeFormat=timestamp", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "v1", + "toJulianTimeByTimestamp" + ], + "query": [ + { + "key": "precision", + "value": "10", + "description": "How many digits after . will be in output. Allowed range: [1, 20]" + }, + { + "key": "timestamp", + "value": "1735693261", + "description": "Timestamp for calculations. Current, if not specified" + }, + { + "key": "timeFormat", + "value": "timestamp", + "description": "Supports: \"ISO\" (default), \"timestamp\" any Go time format directives (without UTC), for example: \"Mon, 02 Jan 2006 15:04:05\"" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Server", + "value": "Fiber" + }, + { + "key": "Date", + "value": "Mon, 17 Nov 2025 04:27:47 GMT" + }, + { + "key": "Content-Type", + "value": "application/json", + "description": "", + "type": "text" + }, + { + "key": "Content-Length", + "value": "56" + } + ], + "cookie": [ + { + "expires": "Invalid Date", + "domain": "", + "path": "" + } + ], + "body": "{\n \"CivilDate\": 1735693261,\n \"JulianDate\": 2460676.5423726854\n}" + } + ] + }, + { + "name": "Get Civil Time by Julian Time", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/v1/fromJulianTime?precision=5&jtime=2460676.5423726854&timeFormat=Mon, 02 Jan 2006 15:04:05", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "v1", + "fromJulianTime" + ], + "query": [ + { + "key": "precision", + "value": "5", + "description": "How many digits after . will be in output. Allowed range: [1, 20]" + }, + { + "key": "jtime", + "value": "2460676.5423726854", + "description": "Julian Time to convert (float64)" + }, + { + "key": "timeFormat", + "value": "Mon, 02 Jan 2006 15:04:05", + "description": "Supports: \"ISO\" (default), \"timestamp\" any Go time format directives (without UTC), for example: \"Mon, 02 Jan 2006 15:04:05\"" + } + ] + } + }, + "response": [ + { + "name": "fromJulianTime", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/v1/fromJulianTime?precision=5&jtime=2460676.5423726854", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "v1", + "fromJulianTime" + ], + "query": [ + { + "key": "precision", + "value": "5", + "description": "How many digits after . will be in output. Allowed range: [1, 20]" + }, + { + "key": "jtime", + "value": "2460676.5423726854", + "description": "Julian Time to convert (float64)" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Server", + "value": "Fiber" + }, + { + "key": "Date", + "value": "Mon, 17 Nov 2025 04:28:25 GMT" + }, + { + "key": "Content-Type", + "value": "application/json", + "name": "Content-Type", + "description": "", + "type": "text" + }, + { + "key": "Content-Length", + "value": "63" + } + ], + "cookie": [], + "body": "{\n \"CivilDate\": \"2025-01-01T01:01:01Z\",\n \"JulianDate\": 2460676.54237\n}" + }, + { + "name": "fromJulianTime — custom timeFormat", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/v1/fromJulianTime?precision=5&jtime=2460676.5423726854&timeFormat=Mon, 02 Jan 2006 15:04:05", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "v1", + "fromJulianTime" + ], + "query": [ + { + "key": "precision", + "value": "5", + "description": "How many digits after . will be in output. Allowed range: [1, 20]" + }, + { + "key": "jtime", + "value": "2460676.5423726854", + "description": "Julian Time to convert (float64)" + }, + { + "key": "timeFormat", + "value": "Mon, 02 Jan 2006 15:04:05", + "description": "Supports: \"ISO\" (default), \"timestamp\" any Go time format directives (without UTC), for example: \"Mon, 02 Jan 2006 15:04:05\"" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ { - "key": "Keep-Alive", - "value": "timeout=900" + "key": "Server", + "value": "Fiber" + }, + { + "key": "Date", + "value": "Mon, 17 Nov 2025 04:30:26 GMT" + }, + { + "key": "Content-Type", + "value": "application/json", + "name": "Content-Type", + "description": "", + "type": "text" + }, + { + "key": "Content-Length", + "value": "68" } ], "cookie": [], - "body": "[\n {\n \"NewMoon\": \"2024-12-31T03:27:49+05:00\",\n \"FirstQuarter\": \"2025-01-07T04:34:13+05:00\",\n \"FullMoon\": \"2025-01-14T03:27:44+05:00\",\n \"LastQuarter\": \"2025-01-22T01:42:58+05:00\"\n },\n {\n \"NewMoon\": \"2025-01-29T17:37:18+05:00\",\n \"FirstQuarter\": \"2025-02-05T12:39:54+05:00\",\n \"FullMoon\": \"2025-02-12T18:54:26+05:00\",\n \"LastQuarter\": \"2025-02-20T22:54:12+05:00\"\n },\n {\n \"NewMoon\": \"2025-02-28T05:46:43+05:00\",\n \"FirstQuarter\": \"2025-03-06T21:17:10+05:00\",\n \"FullMoon\": \"2025-03-14T11:55:56+05:00\",\n \"LastQuarter\": \"2025-03-22T17:09:32+05:00\"\n },\n {\n \"NewMoon\": \"2025-03-29T16:00:07+05:00\",\n \"FirstQuarter\": \"2025-04-05T07:05:24+05:00\",\n \"FullMoon\": \"2025-04-13T05:23:56+05:00\",\n \"LastQuarter\": \"2025-04-21T07:24:10+05:00\"\n },\n {\n \"NewMoon\": \"2025-04-28T00:33:22+05:00\",\n \"FirstQuarter\": \"2025-05-04T18:40:59+05:00\",\n \"FullMoon\": \"2025-05-12T21:58:06+05:00\",\n \"LastQuarter\": \"2025-05-20T17:38:39+05:00\"\n },\n {\n \"NewMoon\": \"2025-05-27T08:04:25+05:00\",\n \"FirstQuarter\": \"2025-06-03T08:18:31+05:00\",\n \"FullMoon\": \"2025-06-11T12:46:06+05:00\",\n \"LastQuarter\": \"2025-06-19T00:39:04+05:00\"\n },\n {\n \"NewMoon\": \"2025-06-25T15:33:30+05:00\",\n \"FirstQuarter\": \"2025-07-02T23:55:45+05:00\",\n \"FullMoon\": \"2025-07-11T01:38:54+05:00\",\n \"LastQuarter\": \"2025-07-18T05:42:32+05:00\"\n },\n {\n \"NewMoon\": \"2025-07-25T00:12:27+05:00\",\n \"FirstQuarter\": \"2025-08-01T17:07:25+05:00\",\n \"FullMoon\": \"2025-08-09T12:57:07+05:00\",\n \"LastQuarter\": \"2025-08-16T10:14:41+05:00\"\n },\n {\n \"NewMoon\": \"2025-08-23T11:07:06+05:00\",\n \"FirstQuarter\": \"2025-08-31T11:05:52+05:00\",\n \"FullMoon\": \"2025-09-07T23:10:41+05:00\",\n \"LastQuarter\": \"2025-09-14T15:47:01+05:00\"\n },\n {\n \"NewMoon\": \"2025-09-22T00:54:36+05:00\",\n \"FirstQuarter\": \"2025-09-30T04:51:14+05:00\",\n \"FullMoon\": \"2025-10-07T08:48:57+05:00\",\n \"LastQuarter\": \"2025-10-13T23:39:48+05:00\"\n },\n {\n \"NewMoon\": \"2025-10-21T17:25:58+05:00\",\n \"FirstQuarter\": \"2025-10-29T21:21:02+05:00\",\n \"FullMoon\": \"2025-11-05T18:20:26+05:00\",\n \"LastQuarter\": \"2025-11-12T10:55:00+05:00\"\n },\n {\n \"NewMoon\": \"2025-11-20T11:48:16+05:00\",\n \"FirstQuarter\": \"2025-11-28T11:44:00+05:00\",\n \"FullMoon\": \"2025-12-05T04:15:18+05:00\",\n \"LastQuarter\": \"2025-12-12T02:04:31+05:00\"\n },\n {\n \"NewMoon\": \"2025-12-20T06:44:25+05:00\",\n \"FirstQuarter\": \"2025-12-27T23:35:58+05:00\",\n \"FullMoon\": \"2026-01-03T15:04:15+05:00\",\n \"LastQuarter\": \"2026-01-10T20:51:36+05:00\"\n }\n]" + "body": "{\n \"CivilDate\": \"Wed, 01 Jan 2025 01:01:01\",\n \"JulianDate\": 2460676.54237\n}" + }, + { + "name": "fromJulianTime — timestamp timeFormat", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/v1/fromJulianTime?precision=5&jtime=2460676.5423726854&timeFormat=timestamp", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "v1", + "fromJulianTime" + ], + "query": [ + { + "key": "precision", + "value": "5", + "description": "How many digits after . will be in output. Allowed range: [1, 20]" + }, + { + "key": "jtime", + "value": "2460676.5423726854", + "description": "Julian Time to convert (float64)" + }, + { + "key": "timeFormat", + "value": "timestamp", + "description": "Supports: \"ISO\" (default), \"timestamp\" any Go time format directives (without UTC), for example: \"Mon, 02 Jan 2006 15:04:05\"" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Server", + "value": "Fiber" + }, + { + "key": "Date", + "value": "Mon, 17 Nov 2025 04:30:57 GMT" + }, + { + "key": "Content-Type", + "value": "application/json", + "name": "Content-Type", + "description": "", + "type": "text" + }, + { + "key": "Content-Length", + "value": "51" + } + ], + "cookie": [], + "body": "{\n \"CivilDate\": 1735693261,\n \"JulianDate\": 2460676.54237\n}" } ] - }, + } + ] + }, + { + "name": "Nearest events", + "item": [ { - "name": "Get moon phases table by current year", + "name": "Next moon phase", "protocolProfileBehavior": { "disableBodyPruning": true }, @@ -562,61 +2581,172 @@ "header": [], "body": { "mode": "raw", - "raw": "", - "options": { - "raw": { - "language": "json" - } - } + "raw": "" }, "url": { - "raw": "{{baseUrl}}/v1/moonTableCurrent?utc=5", + "raw": "{{baseUrl}}/v1/nextMoonPhase?utc=5&timeFormat=Mon, 02 Jan 2006 15:04:05", "host": [ "{{baseUrl}}" ], "path": [ "v1", - "moonTableCurrent" + "nextMoonPhase" ], "query": [ { "key": "utc", "value": "5", "description": "Timezone. Example: \"UTC+5\", \"5\", \"-10:30\"" + }, + { + "key": "timeFormat", + "value": "Mon, 02 Jan 2006 15:04:05", + "description": "How the data will be formed. Available values: ISO (default), timestamp, duration or Go format. Duration is seconds between current date and event time." } ] - }, - "description": "Detailed information:\n\n[https://github.com/prostraction/moon?tab=readme-ov-file#get-v1moontableyear](https://github.com/prostraction/moon?tab=readme-ov-file#get-v1moontableyear)\n\nThe method returns the moon phases for the given year. The response contains an array for each month, each element of which contains the time of the new moon, first quarter, full moon, last quarter." + } }, "response": [ { - "name": "moonTableCurrent", + "name": "nextMoonPhase — custom format", "originalRequest": { "method": "GET", "header": [], - "body": { - "mode": "raw", - "raw": "", - "options": { - "raw": { - "language": "json" + "url": { + "raw": "{{baseUrl}}/v1/nextMoonPhase?utc=5&timeFormat=Mon, 02 Jan 2006 15:04:05", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "v1", + "nextMoonPhase" + ], + "query": [ + { + "key": "utc", + "value": "5", + "description": "Timezone. Example: \"UTC+5\", \"5\", \"-10:30\"" + }, + { + "key": "timeFormat", + "value": "Mon, 02 Jan 2006 15:04:05", + "description": "How the data will be formed. Available values: ISO (default), timestamp, duration or Go format. Duration is seconds between current date and event time." + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Server", + "value": "Fiber" + }, + { + "key": "Date", + "value": "Sun, 16 Nov 2025 18:17:07 GMT" + }, + { + "key": "Content-Type", + "value": "application/json", + "name": "Content-Type", + "description": "", + "type": "text" + }, + { + "key": "Content-Length", + "value": "163" + } + ], + "cookie": [], + "body": "{\n \"NewMoon\": \"Thu, 20 Nov 2025 11:48:16\",\n \"FirstQuarter\": \"Fri, 28 Nov 2025 11:44:00\",\n \"FullMoon\": \"Fri, 05 Dec 2025 04:15:18\",\n \"LastQuarter\": \"Fri, 12 Dec 2025 02:04:31\"\n}" + }, + { + "name": "nextMoonPhase — duration format", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/v1/nextMoonPhase?utc=5&timeFormat=duration", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "v1", + "nextMoonPhase" + ], + "query": [ + { + "key": "utc", + "value": "5", + "description": "Timezone. Example: \"UTC+5\", \"5\", \"-10:30\"" + }, + { + "key": "timeFormat", + "value": "duration", + "description": "How the data will be formed. Available values: ISO (default), timestamp, duration or Go format. Duration is seconds between current date and event time." } - } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Server", + "value": "Fiber" + }, + { + "key": "Date", + "value": "Sun, 16 Nov 2025 15:37:46 GMT" + }, + { + "key": "Content-Type", + "value": "application/json", + "description": "", + "type": "text" }, + { + "key": "Content-Length", + "value": "82" + } + ], + "cookie": [ + { + "expires": "Invalid Date", + "domain": "", + "path": "" + } + ], + "body": "{\n \"NewMoon\": 313830,\n \"FirstQuarter\": 1004774,\n \"FullMoon\": 1582652,\n \"LastQuarter\": 2179605\n}" + }, + { + "name": "nextMoonPhase — ISO format", + "originalRequest": { + "method": "GET", + "header": [], "url": { - "raw": "{{baseUrl}}/v1/moonTableCurrent?utc=5", + "raw": "{{baseUrl}}/v1/nextMoonPhase?utc=5", "host": [ "{{baseUrl}}" ], "path": [ "v1", - "moonTableCurrent" + "nextMoonPhase" ], "query": [ { "key": "utc", "value": "5", "description": "Timezone. Example: \"UTC+5\", \"5\", \"-10:30\"" + }, + { + "key": "timeFormat", + "value": "ISO", + "description": "How the data will be formed. Available values: ISO (default), timestamp, duration or Go format. Duration is seconds between current date and event time.", + "disabled": true } ] } @@ -627,11 +2757,11 @@ "header": [ { "key": "Server", - "value": "nginx/1.24.0 (Ubuntu)" + "value": "Fiber" }, { "key": "Date", - "value": "Tue, 04 Nov 2025 11:31:58 GMT" + "value": "Sun, 16 Nov 2025 15:28:59 GMT" }, { "key": "Content-Type", @@ -642,19 +2772,71 @@ }, { "key": "Content-Length", - "value": "2133" + "value": "163" + } + ], + "cookie": [], + "body": "{\n \"NewMoon\": \"2025-11-20T11:48:16+05:00\",\n \"FirstQuarter\": \"2025-11-28T11:44:00+05:00\",\n \"FullMoon\": \"2025-12-05T04:15:18+05:00\",\n \"LastQuarter\": \"2025-12-12T02:04:31+05:00\"\n}" + }, + { + "name": "nextMoonPhase — timestamp format", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/v1/nextMoonPhase?utc=5&timeFormat=timestamp", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "v1", + "nextMoonPhase" + ], + "query": [ + { + "key": "utc", + "value": "5", + "description": "Timezone. Example: \"UTC+5\", \"5\", \"-10:30\"" + }, + { + "key": "timeFormat", + "value": "timestamp", + "description": "How the data will be formed. Available values: ISO (default), timestamp, duration or Go format. Duration is seconds between current date and event time." + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Server", + "value": "Fiber" }, { - "key": "Connection", - "value": "keep-alive" + "key": "Date", + "value": "Sun, 16 Nov 2025 15:36:45 GMT" }, { - "key": "Keep-Alive", - "value": "timeout=900" + "key": "Content-Type", + "value": "application/json", + "description": "", + "type": "text" + }, + { + "key": "Content-Length", + "value": "95" } ], - "cookie": [], - "body": "[\n {\n \"NewMoon\": \"2024-12-31T03:27:49+05:00\",\n \"FirstQuarter\": \"2025-01-07T04:34:13+05:00\",\n \"FullMoon\": \"2025-01-14T03:27:44+05:00\",\n \"LastQuarter\": \"2025-01-22T01:42:58+05:00\"\n },\n {\n \"NewMoon\": \"2025-01-29T17:37:18+05:00\",\n \"FirstQuarter\": \"2025-02-05T12:39:54+05:00\",\n \"FullMoon\": \"2025-02-12T18:54:26+05:00\",\n \"LastQuarter\": \"2025-02-20T22:54:12+05:00\"\n },\n {\n \"NewMoon\": \"2025-02-28T05:46:43+05:00\",\n \"FirstQuarter\": \"2025-03-06T21:17:10+05:00\",\n \"FullMoon\": \"2025-03-14T11:55:56+05:00\",\n \"LastQuarter\": \"2025-03-22T17:09:32+05:00\"\n },\n {\n \"NewMoon\": \"2025-03-29T16:00:07+05:00\",\n \"FirstQuarter\": \"2025-04-05T07:05:24+05:00\",\n \"FullMoon\": \"2025-04-13T05:23:56+05:00\",\n \"LastQuarter\": \"2025-04-21T07:24:10+05:00\"\n },\n {\n \"NewMoon\": \"2025-04-28T00:33:22+05:00\",\n \"FirstQuarter\": \"2025-05-04T18:40:59+05:00\",\n \"FullMoon\": \"2025-05-12T21:58:06+05:00\",\n \"LastQuarter\": \"2025-05-20T17:38:39+05:00\"\n },\n {\n \"NewMoon\": \"2025-05-27T08:04:25+05:00\",\n \"FirstQuarter\": \"2025-06-03T08:18:31+05:00\",\n \"FullMoon\": \"2025-06-11T12:46:06+05:00\",\n \"LastQuarter\": \"2025-06-19T00:39:04+05:00\"\n },\n {\n \"NewMoon\": \"2025-06-25T15:33:30+05:00\",\n \"FirstQuarter\": \"2025-07-02T23:55:45+05:00\",\n \"FullMoon\": \"2025-07-11T01:38:54+05:00\",\n \"LastQuarter\": \"2025-07-18T05:42:32+05:00\"\n },\n {\n \"NewMoon\": \"2025-07-25T00:12:27+05:00\",\n \"FirstQuarter\": \"2025-08-01T17:07:25+05:00\",\n \"FullMoon\": \"2025-08-09T12:57:07+05:00\",\n \"LastQuarter\": \"2025-08-16T10:14:41+05:00\"\n },\n {\n \"NewMoon\": \"2025-08-23T11:07:06+05:00\",\n \"FirstQuarter\": \"2025-08-31T11:05:52+05:00\",\n \"FullMoon\": \"2025-09-07T23:10:41+05:00\",\n \"LastQuarter\": \"2025-09-14T15:47:01+05:00\"\n },\n {\n \"NewMoon\": \"2025-09-22T00:54:36+05:00\",\n \"FirstQuarter\": \"2025-09-30T04:51:14+05:00\",\n \"FullMoon\": \"2025-10-07T08:48:57+05:00\",\n \"LastQuarter\": \"2025-10-13T23:39:48+05:00\"\n },\n {\n \"NewMoon\": \"2025-10-21T17:25:58+05:00\",\n \"FirstQuarter\": \"2025-10-29T21:21:02+05:00\",\n \"FullMoon\": \"2025-11-05T18:20:26+05:00\",\n \"LastQuarter\": \"2025-11-12T10:55:00+05:00\"\n },\n {\n \"NewMoon\": \"2025-11-20T11:48:16+05:00\",\n \"FirstQuarter\": \"2025-11-28T11:44:00+05:00\",\n \"FullMoon\": \"2025-12-05T04:15:18+05:00\",\n \"LastQuarter\": \"2025-12-12T02:04:31+05:00\"\n },\n {\n \"NewMoon\": \"2025-12-20T06:44:25+05:00\",\n \"FirstQuarter\": \"2025-12-27T23:35:58+05:00\",\n \"FullMoon\": \"2026-01-03T15:04:15+05:00\",\n \"LastQuarter\": \"2026-01-10T20:51:36+05:00\"\n }\n]" + "cookie": [ + { + "expires": "Invalid Date", + "domain": "", + "path": "" + } + ], + "body": "{\n \"NewMoon\": 1763621296,\n \"FirstQuarter\": 1764312240,\n \"FullMoon\": 1764890118,\n \"LastQuarter\": 1765487071\n}" } ] } diff --git a/internal/cache/cache.go b/internal/cache/cache.go new file mode 100644 index 0000000..c374047 --- /dev/null +++ b/internal/cache/cache.go @@ -0,0 +1,7 @@ +package cache + +type moonCache struct { +} + +type positionCache struct { +} diff --git a/internal/server/helpers.go b/internal/server/helpers.go index 8f8f504..d6d3be5 100644 --- a/internal/server/helpers.go +++ b/internal/server/helpers.go @@ -10,12 +10,12 @@ func round(num float64) int { return int(num + math.Copysign(0.5, num)) } -func toFixed(num float64, precision int) float64 { +func ToFixed(num float64, precision int) float64 { output := math.Pow(10, float64(precision)) return float64(round(num*output)) / output } -func strToInt(val string, fallback int, min int, max int) int { +func StrToInt(val string, fallback int, min int, max int) int { v, err := strconv.Atoi(val) if err != nil { v = fallback @@ -48,7 +48,7 @@ func parseCoords(latStr, lonStr string) Coordinates { return locationCords } -func isValidDate(year, month, day int) error { +func IsValidDate(year, month, day int) error { if year < 0 || year > 9999 { return errors.New("'year' should be in range [0,9999]") } diff --git a/internal/server/models.go b/internal/server/models.go index 7899d5a..f7f9fef 100644 --- a/internal/server/models.go +++ b/internal/server/models.go @@ -8,14 +8,15 @@ import ( "time" ) -type MoonTable struct { - Table []*moon.MoonTableElement +type ErrorPrintable struct { + Status int + Message string } type MoonStat struct { MoonDays float64 Illumination float64 - Phase phase.PhaseResp + Phase *phase.Phase Zodiac zodiac.Zodiac Position *pos.MoonPosition `json:"MoonPosition,omitempty"` } @@ -36,16 +37,16 @@ type MoonDay struct { } type MoonPhaseResponse struct { - BeginDay *MoonStat - CurrentState *MoonStat - EndDay *MoonStat + BeginDay *MoonStat `json:"BeginDay,omitempty"` + CurrentState *MoonStat `json:"CurrentState,omitempty"` + EndDay *MoonStat `json:"EndDay,omitempty"` MoonDaysDetailed *moon.MoonDaysDetailed `json:"MoonDaysDetailed,omitempty"` ZodiacDetailed *zodiac.Zodiacs MoonRiseAndSet *pos.DayData `json:"MoonRiseAndSet,omitempty"` - info *FullInfo + //info *FullInfo } type Coordinates struct { @@ -53,3 +54,8 @@ type Coordinates struct { Longitude float64 IsValid bool } + +type JulianTimeResp struct { + CivilDate *any + JulianDate float64 +} diff --git a/internal/server/route-jtime.go b/internal/server/route-jtime.go new file mode 100644 index 0000000..8d06397 --- /dev/null +++ b/internal/server/route-jtime.go @@ -0,0 +1,115 @@ +package server + +import ( + "strconv" + "strings" + "time" + + "github.com/gofiber/fiber/v2" + + jt "moon/pkg/julian-time" +) + +/* Julian Time methods */ +func (s *Server) toJulianTimeByDateV1(c *fiber.Ctx) error { + tNow := time.Now() + tNow = tNow.In(time.UTC) + + precision := StrToInt(c.Query("precision", "2"), 2, 0, 20) + + year := StrToInt(c.Query("year", strconv.Itoa(tNow.Year())), tNow.Year(), 1, 9999) + month := StrToInt(c.Query("month", strconv.Itoa(int(tNow.Month()))), int(tNow.Month()), 1, 12) + day := StrToInt(c.Query("day", strconv.Itoa(int(tNow.Day()))), int(tNow.Day()), 1, 31) + + timeFormat := c.Query("timeFormat", "ISO") + + err := IsValidDate(year, month, day) + if err != nil { + c.Status(400) + errPrintable := ErrorPrintable{ + Status: 400, + Message: "Validation error: " + err.Error(), + } + return c.JSON(errPrintable) + } + + hour := StrToInt(c.Query("hour", strconv.Itoa(int(tNow.Hour()))), int(tNow.Hour()), 0, 23) + minute := StrToInt(c.Query("minute", strconv.Itoa(int(tNow.Minute()))), int(tNow.Minute()), 0, 59) + second := StrToInt(c.Query("second", strconv.Itoa(int(tNow.Second()))), int(tNow.Second()), 0, 59) + + tGiven := time.Date(year, jt.GetMonth(month), day, hour, minute, second, 0, time.UTC) + + resp := s.toJulianTimeV1(c, tGiven, timeFormat, precision) + return c.JSON(resp) +} + +func (s *Server) toJulianTimeByTimestampV1(c *fiber.Ctx) error { + tStr := c.Query("timestamp", strconv.FormatInt(time.Now().Unix(), 10)) + t, err := strconv.ParseInt(tStr, 10, 64) + if err != nil { + t = time.Now().Unix() + } + + timeFormat := c.Query("timeFormat", "ISO") + precision := StrToInt(c.Query("precision", "2"), 2, 0, 20) + + tm := time.Unix(t, 0) + tGiven := time.Date(tm.Year(), tm.Month(), tm.Day(), tm.Hour(), tm.Minute(), tm.Second(), 0, time.Local) + tGiven = tGiven.In(time.UTC) + + resp := s.toJulianTimeV1(c, tGiven, timeFormat, precision) + return c.JSON(resp) +} + +func (s *Server) toJulianTimeV1(c *fiber.Ctx, tGiven time.Time, timeFormat string, precision int) JulianTimeResp { + resp := JulianTimeResp{} + + var t any + if strings.ToLower(timeFormat) == "timestamp" { + t = tGiven.Unix() + } else if strings.ToLower(timeFormat) != "iso" { + t = tGiven.Format(timeFormat) + } else { + t = tGiven + } + + resp.CivilDate = &t + resp.JulianDate = ToFixed(jt.ToJulianDate(tGiven), precision) + return resp +} + +func (s *Server) fromJulianTimeV1(c *fiber.Ctx) error { + utc := c.Query("utc", "UTC:+0") + loc, _ := jt.SetTimezoneLocFromString(utc) + + jtStr := c.Query("jtime", "none") + jtime, err := strconv.ParseFloat(jtStr, 64) + if err != nil { + c.Status(400) + errPrintable := ErrorPrintable{ + Status: 400, + Message: "missing required parameter: 'jtime' (float)", + } + return c.JSON(errPrintable) + } + + t := jt.FromJulianDate(jtime, loc) + + precision := StrToInt(c.Query("precision", "2"), 2, 0, 20) + timeFormat := c.Query("timeFormat", "ISO") + + var tFormat any + if strings.ToLower(timeFormat) == "timestamp" { + tFormat = t.Unix() + } else if strings.ToLower(timeFormat) != "iso" { + tFormat = t.Format(timeFormat) + } else { + tFormat = t + } + + resp := JulianTimeResp{} + resp.CivilDate = &tFormat + resp.JulianDate = ToFixed(jtime, precision) + + return c.JSON(resp) +} diff --git a/internal/server/route-moon-table.go b/internal/server/route-moon-table.go new file mode 100644 index 0000000..9f71f3d --- /dev/null +++ b/internal/server/route-moon-table.go @@ -0,0 +1,71 @@ +package server + +import ( + jt "moon/pkg/julian-time" + "moon/pkg/moon" + "strconv" + "strings" + "time" + + "github.com/gofiber/fiber/v2" +) + +/* MOON TABLE */ +func (s *Server) moonTableCurrentV1(c *fiber.Ctx) error { + utc := c.Query("utc", "UTC:+0") + loc, _ := jt.SetTimezoneLocFromString(utc) + /*if err != nil { + log.Println(err) + }*/ + + timeFormat := c.Query("timeFormat", "ISO") + + tGiven := time.Date(time.Now().Year(), time.Now().Month(), time.Now().Day(), time.Now().Hour(), time.Now().Minute(), time.Now().Second(), 0, loc) + return s.moonTableV1(c, timeFormat, tGiven) +} + +func (s *Server) moonTableYearV1(c *fiber.Ctx) error { + utc := c.Query("utc", "UTC:+0") + loc, _ := jt.SetTimezoneLocFromString(utc) + /*if err != nil { + log.Println(err) + }*/ + + timeFormat := c.Query("timeFormat", "ISO") + + tNow := time.Now() + year := StrToInt(c.Query("year", strconv.Itoa(tNow.Year())), tNow.Year(), 1, 9999) + + tGiven := time.Date(year, time.January, 1, 0, 0, 0, 0, loc) + return s.moonTableV1(c, timeFormat, tGiven) +} + +func (s *Server) moonTableV1(c *fiber.Ctx, timeFormat string, tGiven time.Time) error { + moonTable := moon.CreateMoonTable(tGiven) + + if strings.ToLower(timeFormat) == "timestamp" { + val := []moon.NearestPhaseTimestamp{} + for i := range moonTable.Elems { + val = append(val, moon.NearestPhaseTimestamp{ + NewMoon: moonTable.Elems[i].NewMoon.Unix(), + FirstQuarter: moonTable.Elems[i].FirstQuarter.Unix(), + FullMoon: moonTable.Elems[i].FullMoon.Unix(), + LastQuarter: moonTable.Elems[i].FullMoon.Unix(), + }) + } + return c.JSON(val) + } else if strings.ToLower(timeFormat) != "iso" { + val := []moon.NearestPhaseString{} + for i := range moonTable.Elems { + val = append(val, moon.NearestPhaseString{ + NewMoon: moonTable.Elems[i].NewMoon.Format(timeFormat), + FirstQuarter: moonTable.Elems[i].FirstQuarter.Format(timeFormat), + FullMoon: moonTable.Elems[i].FullMoon.Format(timeFormat), + LastQuarter: moonTable.Elems[i].FullMoon.Format(timeFormat), + }) + } + return c.JSON(val) + } + + return c.JSON(moonTable.Elems) +} diff --git a/internal/server/route-next.go b/internal/server/route-next.go new file mode 100644 index 0000000..6cd0a90 --- /dev/null +++ b/internal/server/route-next.go @@ -0,0 +1,104 @@ +package server + +import ( + jt "moon/pkg/julian-time" + "moon/pkg/moon" + "strconv" + "strings" + "time" + + "github.com/gofiber/fiber/v2" + "github.com/gofiber/fiber/v2/log" +) + +func (s *Server) moonNextMoonPhaseV1(c *fiber.Ctx) error { + utc := c.Query("utc", "UTC:+0") + loc, _ := jt.SetTimezoneLocFromString(utc) + tGiven := time.Date(time.Now().Year(), time.Now().Month(), time.Now().Day(), time.Now().Hour(), time.Now().Minute(), time.Now().Second(), time.Now().Nanosecond(), time.Local) + tGiven = tGiven.In(loc) + + moonTable := moon.CreateMoonTable(tGiven) + np := moon.FindNearestPhase(tGiven, moonTable) + + format := c.Query("timeFormat", "ISO") + if strings.ToLower(format) == "timestamp" { + npt := moon.NearestPhaseTimestamp{ + NewMoon: np.NewMoon.Unix(), + FirstQuarter: np.FirstQuarter.Unix(), + FullMoon: np.FullMoon.Unix(), + LastQuarter: np.LastQuarter.Unix(), + } + return c.JSON(npt) + } else if strings.ToLower(format) == "duration" { + npd := moon.NearestPhaseTimestamp{ + NewMoon: np.NewMoon.Unix() - tGiven.Unix(), + FirstQuarter: np.FirstQuarter.Unix() - tGiven.Unix(), + FullMoon: np.FullMoon.Unix() - tGiven.Unix(), + LastQuarter: np.LastQuarter.Unix() - tGiven.Unix(), + } + return c.JSON(npd) + } else if strings.ToLower(format) == "iso" { + return c.JSON(np) + } else { + npc := moon.NearestPhaseString{ + NewMoon: np.NewMoon.Format(format), + FirstQuarter: np.FirstQuarter.Format(format), + FullMoon: np.FullMoon.Format(format), + LastQuarter: np.LastQuarter.Format(format), + } + return c.JSON(npc) + } +} + +func (s *Server) moonNextMoonDayV1(c *fiber.Ctx) error { + utc := c.Query("utc", "UTC:+0") + loc, _ := jt.SetTimezoneLocFromString(utc) + day := c.Query("day", "not-set") + if day == "not-set" { + e := ErrorPrintable{Status: 400, Message: "day is required for this method."} + return c.JSON(e) + } + dayInt, err := strconv.Atoi(day) + if err != nil { + e := ErrorPrintable{Status: 400, Message: "day is required to be int."} + return c.JSON(e) + } + if dayInt < 0 || dayInt > 30 { + e := ErrorPrintable{Status: 400, Message: "day is required to be [0, 30]. No other days allowed!"} + return c.JSON(e) + } + + tGiven := time.Date(time.Now().Year(), time.Now().Month(), time.Now().Day(), time.Now().Hour(), time.Now().Minute(), time.Now().Second(), time.Now().Nanosecond(), time.Local) + tGiven = tGiven.In(loc) + + moonTable := moon.CreateMoonTable(tGiven) + resp, err := moon.SearchMoonDay(tGiven, moonTable, dayInt) + if err != nil { + log.Error(err) + e := ErrorPrintable{Status: 500, Message: "bad things happen: " + err.Error()} + return c.JSON(e) + } + + format := c.Query("timeFormat", "ISO") + if strings.ToLower(format) == "timestamp" { + resp := moon.SeachMoonDayRespTimestamp{ + From: resp.From.Unix(), + To: resp.To.Unix(), + } + return c.JSON(resp) + } else if strings.ToLower(format) == "duration" { + resp := moon.SeachMoonDayRespTimestamp{ + From: resp.From.Unix() - tGiven.Unix(), + To: resp.To.Unix() - tGiven.Unix(), + } + return c.JSON(resp) + } else if strings.ToLower(format) == "iso" { + return c.JSON(resp) + } else { + resp := moon.SeachMoonDayRespString{ + From: resp.From.Format(format), + To: resp.To.Format(format), + } + return c.JSON(resp) + } +} diff --git a/internal/server/route-phase.go b/internal/server/route-phase.go new file mode 100644 index 0000000..00ecf35 --- /dev/null +++ b/internal/server/route-phase.go @@ -0,0 +1,173 @@ +package server + +import ( + jt "moon/pkg/julian-time" + "moon/pkg/moon" + "moon/pkg/phase" + pos "moon/pkg/position" + "moon/pkg/zodiac" + "strconv" + "time" + + "github.com/gofiber/fiber/v2" + "github.com/gofiber/fiber/v2/log" +) + +/* MOON PHASE */ +func (s *Server) moonPhaseCurrentV1(c *fiber.Ctx) error { + utc := c.Query("utc", "UTC:+0") + loc, err := jt.SetTimezoneLocFromString(utc) + if err != nil { + log.Trace(err) + } + tGiven := time.Date(time.Now().Year(), time.Now().Month(), time.Now().Day(), time.Now().Hour(), time.Now().Minute(), time.Now().Second(), 0, time.Local) + tGiven = tGiven.In(loc) + precision := StrToInt(c.Query("precision", "2"), 2, 0, 20) + + latStr := c.Query("latitude", "no-value") + lonStr := c.Query("longitude", "no-value") + locationCords := parseCoords(latStr, lonStr) + + timeFormat := c.Query("timeFormat", "ISO") + + return s.moonPhaseV1(c, tGiven, precision, locationCords, timeFormat) +} + +func (s *Server) moonPhaseTimestampV1(c *fiber.Ctx) error { + utc := c.Query("utc", "UTC:+0") + loc, err := jt.SetTimezoneLocFromString(utc) + if err != nil { + log.Trace(err) + } + + tStr := c.Query("timestamp", strconv.FormatInt(time.Now().Unix(), 10)) + t, err := strconv.ParseInt(tStr, 10, 64) + if err != nil { + t = time.Now().Unix() + } + + tm := time.Unix(t, 0) + tGiven := time.Date(tm.Year(), tm.Month(), tm.Day(), tm.Hour(), tm.Minute(), tm.Second(), 0, time.Local).In(loc) + + precision := StrToInt(c.Query("precision", "2"), 2, 0, 20) + + latStr := c.Query("latitude", "no-value") + lonStr := c.Query("longitude", "no-value") + locationCords := parseCoords(latStr, lonStr) + + timeFormat := c.Query("timeFormat", "ISO") + + return s.moonPhaseV1(c, tGiven, precision, locationCords, timeFormat) +} + +func (s *Server) moonPhaseDatetV1(c *fiber.Ctx) error { + utc := c.Query("utc", "UTC:+0") + loc, err := jt.SetTimezoneLocFromString(utc) + if err != nil { + log.Trace(err) + } + + tNow := time.Now() + + year := StrToInt(c.Query("year", strconv.Itoa(tNow.Year())), tNow.Year(), 1, 9999) + month := StrToInt(c.Query("month", strconv.Itoa(int(tNow.Month()))), int(tNow.Month()), 1, 12) + day := StrToInt(c.Query("day", strconv.Itoa(int(tNow.Day()))), int(tNow.Day()), 1, 31) + + err = IsValidDate(year, month, day) + if err != nil { + c.Status(400) + errPrintable := ErrorPrintable{ + Status: 400, + Message: "Validation error: " + err.Error(), + } + return c.JSON(errPrintable) + } + + hour := StrToInt(c.Query("hour", strconv.Itoa(int(tNow.Hour()))), int(tNow.Hour()), 0, 23) + minute := StrToInt(c.Query("minute", strconv.Itoa(int(tNow.Minute()))), int(tNow.Minute()), 0, 59) + second := StrToInt(c.Query("second", strconv.Itoa(int(tNow.Second()))), int(tNow.Second()), 0, 59) + + precision := StrToInt(c.Query("precision", "2"), 2, 0, 20) + + latStr := c.Query("latitude", "no-value") + lonStr := c.Query("longitude", "no-value") + locationCords := parseCoords(latStr, lonStr) + + timeFormat := c.Query("timeFormat", "ISO") + + tGiven := time.Date(year, jt.GetMonth(month), day, hour, minute, second, 0, time.Local) + tGiven = tGiven.In(loc) + return s.moonPhaseV1(c, tGiven, precision, locationCords, timeFormat) +} + +func (s *Server) moonPhaseV1(c *fiber.Ctx, tGiven time.Time, precision int, locationCords Coordinates, timeFormat string) error { + var err error + + lang := c.Query("lang", "en") + utc := c.Query("utc", "UTC:+0") + + loc, err := jt.SetTimezoneLocFromString(utc) + if err != nil { + log.Trace(err) + } + + resp := MoonPhaseResponse{} + resp.BeginDay = new(MoonStat) + resp.CurrentState = new(MoonStat) + resp.EndDay = new(MoonStat) + + moonTable := moon.CreateMoonTable(tGiven) + + // moon days + day := moon.CurrentMoonDays(tGiven, loc, moonTable) + + resp.BeginDay.MoonDays = ToFixed(day.Begin.Minutes()/jt.Fminute, precision) + resp.CurrentState.MoonDays = ToFixed(day.Current.Minutes()/jt.Fminute, precision) + resp.EndDay.MoonDays = ToFixed(day.End.Minutes()/jt.Fminute, precision) + + // phase && illum + phase := phase.CurrentMoonPhase(tGiven, lang) + + resp.BeginDay.Illumination = ToFixed(phase.Illumination.BeginDay*100, precision) + resp.CurrentState.Illumination = ToFixed(phase.Illumination.Current*100, precision) + resp.EndDay.Illumination = ToFixed(phase.Illumination.EndDay*100, precision) + + resp.BeginDay.Phase = phase.BeginDay + resp.CurrentState.Phase = phase.Current + resp.EndDay.Phase = phase.EndDay + + // zodiac TO DO refactor + resp.ZodiacDetailed, resp.BeginDay.Zodiac, resp.CurrentState.Zodiac, resp.EndDay.Zodiac = zodiac.CurrentZodiacs(tGiven, loc, lang, timeFormat, moonTable.Elems) + + if locationCords.IsValid { + resp.MoonRiseAndSet, err = s.positionCache.GetRisesDay(tGiven.Year(), int(tGiven.Month()), tGiven.Day(), tGiven.Location(), precision, timeFormat, locationCords.Longitude, locationCords.Latitude) + if err != nil { + log.Error(err) + } + resp.MoonDaysDetailed = moon.MoonDetailed(tGiven, loc, lang, timeFormat, locationCords.Longitude, locationCords.Latitude) + + newT := time.Date(tGiven.Year(), tGiven.Month(), tGiven.Day(), 0, 0, 0, 0, tGiven.Location()) + resp.BeginDay.Position, err = pos.GetMoonPosition(newT, newT.Location(), precision, timeFormat, locationCords.Longitude, locationCords.Latitude) + if err != nil { + log.Error(err) + } + + resp.CurrentState.Position, err = pos.GetMoonPosition(tGiven, tGiven.Location(), precision, timeFormat, locationCords.Longitude, locationCords.Latitude) + if err != nil { + log.Error(err) + } + + resp.EndDay.Position, err = pos.GetMoonPosition(newT.AddDate(0, 0, 1), newT.AddDate(0, 0, 1).Location(), precision, timeFormat, locationCords.Longitude, locationCords.Latitude) + if err != nil { + log.Error(err) + } + } else { + resp.MoonRiseAndSet, err = s.positionCache.GetRisesDay(tGiven.Year(), int(tGiven.Month()), tGiven.Day(), tGiven.Location(), precision, timeFormat) + } + + if err != nil && err.Error() != "no location prodived" { + log.Error(err.Error()) + } + + return c.JSON(resp) +} diff --git a/internal/server/route-position.go b/internal/server/route-position.go new file mode 100644 index 0000000..e581f83 --- /dev/null +++ b/internal/server/route-position.go @@ -0,0 +1,49 @@ +package server + +import ( + jt "moon/pkg/julian-time" + "strconv" + "strings" + "time" + + "github.com/gofiber/fiber/v2" +) + +func (s *Server) moonPositionMonthly(c *fiber.Ctx) error { + utc := c.Query("utc", "UTC:+0") + loc, _ := jt.SetTimezoneLocFromString(utc) + + tNow := time.Now() + year := StrToInt(c.Query("year", strconv.Itoa(tNow.Year())), tNow.Year(), 1, 9999) + month := StrToInt(c.Query("month", strconv.Itoa(int(tNow.Month()))), int(tNow.Month()), 1, 12) + + precision := StrToInt(c.Query("precision", "2"), 2, 0, 20) + + latStr := c.Query("latitude", "no-value") + lonStr := c.Query("longitude", "no-value") + locationCords := parseCoords(latStr, lonStr) + + timeFormat := c.Query("timeFormat", "ISO") + + if !locationCords.IsValid { + e := ErrorPrintable{} + e.Status = 400 + e.Message = "latitude and longitude are required for this method." + return c.JSON(e) + } + + if resp, err := s.positionCache.GetRisesMonthly(year, month, loc, precision, timeFormat, locationCords.Longitude, locationCords.Latitude); err == nil { + return c.JSON(resp) + } else { + e := ErrorPrintable{} + if strings.Contains(err.Error(), "400 Bad Request") { + e.Status = 400 + c.Status(400) + } else { + e.Status = 500 + c.Status(500) + } + e.Message = err.Error() + return c.JSON(e) + } +} diff --git a/internal/server/routes.go b/internal/server/routes.go deleted file mode 100644 index fde32c8..0000000 --- a/internal/server/routes.go +++ /dev/null @@ -1,192 +0,0 @@ -package server - -import ( - jt "moon/pkg/julian-time" - phase "moon/pkg/phase" - pos "moon/pkg/position" - zodiac "moon/pkg/zodiac" - "strconv" - "time" - - "github.com/gofiber/fiber/v2" - "github.com/gofiber/fiber/v2/log" -) - -func (s *Server) versionV1(c *fiber.Ctx) error { - return c.JSON("1.1.2") -} - -/* MOON PHASE */ -func (s *Server) moonPhaseCurrentV1(c *fiber.Ctx) error { - utc := c.Query("utc", "UTC:+0") - loc, _ := jt.SetTimezoneLocFromString(utc) - /*if err != nil { - log.Println(err) - }*/ - tGiven := time.Date(time.Now().Year(), time.Now().Month(), time.Now().Day(), time.Now().Hour(), time.Now().Minute(), time.Now().Second(), 0, loc) - precision := strToInt(c.Query("precision", "2"), 2, 0, 20) - - latStr := c.Query("latitude", "no-value") - lonStr := c.Query("longitude", "no-value") - locationCords := parseCoords(latStr, lonStr) - - return s.moonPhaseV1(c, tGiven, precision, locationCords) -} - -func (s *Server) moonPhaseTimestampV1(c *fiber.Ctx) error { - utc := c.Query("utc", "UTC:+0") - loc, _ := jt.SetTimezoneLocFromString(utc) - /*if err != nil { - log.Println(err) - }*/ - - tStr := c.Query("timestamp", strconv.FormatInt(time.Now().Unix(), 10)) - t, err := strconv.ParseInt(tStr, 10, 64) - if err != nil { - t = time.Now().Unix() - } - tm := time.Unix(t, 0) - tGiven := time.Date(tm.Year(), tm.Month(), tm.Day(), tm.Hour(), tm.Minute(), tm.Second(), 0, loc) - - precision := strToInt(c.Query("precision", "2"), 2, 0, 20) - - latStr := c.Query("latitude", "no-value") - lonStr := c.Query("longitude", "no-value") - locationCords := parseCoords(latStr, lonStr) - - return s.moonPhaseV1(c, tGiven, precision, locationCords) -} - -func (s *Server) moonPhaseDatetV1(c *fiber.Ctx) error { - utc := c.Query("utc", "UTC:+0") - loc, _ := jt.SetTimezoneLocFromString(utc) - /*if err != nil { - log.Println(err) - }*/ - - tNow := time.Now() - - year := strToInt(c.Query("year", strconv.Itoa(tNow.Year())), tNow.Year(), 1, 9999) - month := strToInt(c.Query("month", strconv.Itoa(int(tNow.Month()))), int(tNow.Month()), 1, 12) - day := strToInt(c.Query("day", strconv.Itoa(int(tNow.Day()))), int(tNow.Day()), 1, 31) - - err := isValidDate(year, month, day) - if err != nil { - c.Status(400) - return c.SendString("Validation error: " + err.Error()) - } - - hour := strToInt(c.Query("hour", strconv.Itoa(int(tNow.Hour()))), int(tNow.Hour()), 0, 23) - minute := strToInt(c.Query("minute", strconv.Itoa(int(tNow.Minute()))), int(tNow.Minute()), 0, 59) - second := strToInt(c.Query("second", strconv.Itoa(int(tNow.Second()))), int(tNow.Second()), 0, 59) - - precision := strToInt(c.Query("precision", "2"), 2, 0, 20) - - latStr := c.Query("latitude", "no-value") - lonStr := c.Query("longitude", "no-value") - locationCords := parseCoords(latStr, lonStr) - - tGiven := time.Date(year, jt.GetMonth(month), day, hour, minute, second, 0, loc) - return s.moonPhaseV1(c, tGiven, precision, locationCords) -} - -func (s *Server) moonPhaseV1(c *fiber.Ctx, tGiven time.Time, precision int, locationCords Coordinates) error { - lang := c.Query("lang", "en") - utc := c.Query("utc", "UTC:+0") - loc, _ := jt.SetTimezoneLocFromString(utc) - /*if err != nil { - log.Println(err) - }*/ - - resp := MoonPhaseResponse{} - resp.EndDay = new(MoonStat) - resp.CurrentState = new(MoonStat) - resp.BeginDay = new(MoonStat) - resp.info = new(FullInfo) - - var err error - - var beginDuration, currentDuration, endDuration time.Duration - beginDuration, currentDuration, endDuration = s.moonCache.CurrentMoonDays(tGiven, loc) - - resp.info.MoonDaysBegin = beginDuration.Minutes() / jt.Fminute - resp.info.MoonDaysCurrent = currentDuration.Minutes() / jt.Fminute - resp.info.MoonDaysEnd = endDuration.Minutes() / jt.Fminute - - resp.BeginDay.MoonDays = toFixed(resp.info.MoonDaysBegin, precision) - resp.CurrentState.MoonDays = toFixed(resp.info.MoonDaysCurrent, precision) - resp.EndDay.MoonDays = toFixed(resp.info.MoonDaysEnd, precision) - - resp.info.IlluminationCurrent, resp.info.IlluminationBeginDay, resp.info.IlluminationEndDay, resp.CurrentState.Phase, resp.BeginDay.Phase, resp.EndDay.Phase = phase.CurrentMoonPhase(tGiven, lang) - - resp.BeginDay.Illumination = toFixed(resp.info.IlluminationBeginDay*100, precision) - resp.CurrentState.Illumination = toFixed(resp.info.IlluminationCurrent*100, precision) - resp.EndDay.Illumination = toFixed(resp.info.IlluminationEndDay*100, precision) - - resp.ZodiacDetailed, resp.BeginDay.Zodiac, resp.CurrentState.Zodiac, resp.EndDay.Zodiac = zodiac.CurrentZodiacs(tGiven, loc, lang, s.moonCache.CreateMoonTable(tGiven)) - - if locationCords.IsValid { - resp.MoonRiseAndSet, err = pos.GetRisesDay(tGiven.Year(), int(tGiven.Month()), tGiven.Day(), tGiven.Location(), precision, locationCords.Longitude, locationCords.Latitude) - if err != nil { - log.Error(err) - } - resp.MoonDaysDetailed = s.moonCache.MoonDetailed(tGiven, loc, lang, locationCords.Longitude, locationCords.Latitude) - - newT := time.Date(tGiven.Year(), tGiven.Month(), tGiven.Day(), 0, 0, 0, 0, tGiven.Location()) - resp.BeginDay.Position, err = pos.GetMoonPosition(newT, newT.Location(), precision, locationCords.Longitude, locationCords.Latitude) - if err != nil { - log.Error(err) - } - - resp.CurrentState.Position, err = pos.GetMoonPosition(tGiven, tGiven.Location(), precision, locationCords.Longitude, locationCords.Latitude) - if err != nil { - log.Error(err) - } - - resp.EndDay.Position, err = pos.GetMoonPosition(newT.AddDate(0, 0, 1), newT.AddDate(0, 0, 1).Location(), precision, locationCords.Longitude, locationCords.Latitude) - if err != nil { - log.Error(err) - } - } else { - resp.MoonRiseAndSet, err = pos.GetRisesDay(tGiven.Year(), int(tGiven.Month()), tGiven.Day(), tGiven.Location(), precision) - } - - if err != nil && err.Error() != "no location prodived" { - log.Error(err.Error()) - } - - return c.JSON(resp) -} - -/* MOON TABLE */ - -func (s *Server) moonTableCurrentV1(c *fiber.Ctx) error { - utc := c.Query("utc", "UTC:+0") - loc, _ := jt.SetTimezoneLocFromString(utc) - /*if err != nil { - log.Println(err) - }*/ - - tGiven := time.Date(time.Now().Year(), time.Now().Month(), time.Now().Day(), time.Now().Hour(), time.Now().Minute(), time.Now().Second(), 0, loc) - return s.moonTableV1(c, tGiven) -} - -func (s *Server) moonTableYearV1(c *fiber.Ctx) error { - utc := c.Query("utc", "UTC:+0") - loc, _ := jt.SetTimezoneLocFromString(utc) - /*if err != nil { - log.Println(err) - }*/ - - tNow := time.Now() - year := strToInt(c.Query("year", strconv.Itoa(tNow.Year())), tNow.Year(), 1, 9999) - - tGiven := time.Date(year, time.January, 1, 0, 0, 0, 0, loc) - return s.moonTableV1(c, tGiven) -} - -func (s *Server) moonTableV1(c *fiber.Ctx, tGiven time.Time) error { - resp := MoonTable{} - resp.Table = s.moonCache.GenerateMoonTable(tGiven) - return c.JSON(resp.Table) -} diff --git a/internal/server/server.go b/internal/server/server.go index 0081c89..756d335 100644 --- a/internal/server/server.go +++ b/internal/server/server.go @@ -1,22 +1,29 @@ package server import ( - "moon/pkg/moon" + "moon/pkg/position" + "time" "github.com/gofiber/fiber/v2" "github.com/gofiber/fiber/v2/middleware/cors" ) type Server struct { - moonCache *moon.Cache + //moonCache *moon.Cache + positionCache *position.Cache } func (s *Server) NewRouter() *fiber.App { app := fiber.New(fiber.Config{ - Prefork: true, - ServerHeader: "Fiber", - CaseSensitive: false, - StrictRouting: true, + Prefork: true, + ServerHeader: "", + CaseSensitive: false, + StrictRouting: false, + ReadTimeout: 60 * time.Second, + WriteTimeout: 60 * time.Second, + DisableKeepalive: true, + DisableStartupMessage: true, + DisablePreParseMultipartForm: true, }) app.Use(cors.New(cors.Config{ @@ -41,12 +48,7 @@ func (s *Server) NewRouter() *fiber.App { // maybe rename moonPhase -> phase later // moon phase for day: - // - begin, current, end of the day: - // - moon days, illumintaion, phase, zodiac - // - moon days by time - // - zodiacs by time - // - rise, set and meridian: - // - time, direction, azimuth, exists + app.Get("/v1/moonPhaseCurrent", s.moonPhaseCurrentV1) app.Get("/v1/moonPhaseTimestamp", s.moonPhaseTimestampV1) app.Get("/v1/moonPhaseDate", s.moonPhaseDatetV1) @@ -54,12 +56,13 @@ func (s *Server) NewRouter() *fiber.App { app.Get("/api/v1/moonPhaseTimestamp", s.moonPhaseTimestampV1) app.Get("/api/v1/moonPhaseDate", s.moonPhaseDatetV1) - // maybe rename "moon*" -> "*" // per month + app.Get("/v1/moonPositionMonthly", s.moonPositionMonthly) + app.Get("/api/v1/moonPositionMonthly", s.moonPositionMonthly) //app.Get("/v1/moonRiseSetCalendar") //app.Get("/v1/moonPhaseCalendar") //app.Get("/v1/moonZodiacCalendar") - //app.Get("/v1/moonMonthCalendar") -- all combined? think more + //app.Get("/v1/moonMonthCalendar") -- all combined? think more.... // eclipses //app.Get("/v1/moonEclipseYear") @@ -68,11 +71,10 @@ func (s *Server) NewRouter() *fiber.App { //app.Get("/v1/sunEclipseCalendar") // methods when? - //app.Get("/v1/nextMoonPhase") - //app.Get("/v1/nextMoonPhaseFull") - //app.Get("/v1/nextMoonPhaseNew") - //app.Get("/v1/nextMoonPhaseFirst") - //app.Get("/v1/nextMoonPhaseThird") + app.Get("/v1/nextMoonPhase", s.moonNextMoonPhaseV1) + app.Get("/v1/nextMoonDay", s.moonNextMoonDayV1) + app.Get("/api/v1/nextMoonPhase", s.moonNextMoonPhaseV1) + app.Get("/api/v1/nextMoonDay", s.moonNextMoonDayV1) //app.Get("/v1/nextMoonEclipse") //app.Get("/v1/nextSunEclipse") @@ -81,8 +83,13 @@ func (s *Server) NewRouter() *fiber.App { //app.Get("/v1/nextMoonRise") // jtime methods: - //app.Get("/v1/toJulianTime") - //app.Get("/v1/fromJulianTime") + app.Get("/v1/toJulianTimeByDate", s.toJulianTimeByDateV1) + app.Get("/v1/toJulianTimeByTimestamp", s.toJulianTimeByTimestampV1) + app.Get("/v1/fromJulianTime", s.fromJulianTimeV1) + + app.Get("/api/v1/toJulianTimeByDate", s.toJulianTimeByDateV1) + app.Get("/api/v1/toJulianTimeByTimestamp", s.toJulianTimeByTimestampV1) + app.Get("/api/v1/fromJulianTime", s.fromJulianTimeV1) // some kind of faq //app.Get("/v1") @@ -91,6 +98,11 @@ func (s *Server) NewRouter() *fiber.App { app.Get("/v1/version", s.versionV1) app.Get("/api/v1/version", s.versionV1) - s.moonCache = new(moon.Cache) + //s.moonCache = new(moon.Cache) + s.positionCache = new(position.Cache) return app } + +func (s *Server) versionV1(c *fiber.Ctx) error { + return c.JSON("1.2.0rc7-hotfix-2") +} diff --git a/pkg/illumination/illumination.go b/pkg/illumination/illumination.go index 922b5f7..1a349a6 100644 --- a/pkg/illumination/illumination.go +++ b/pkg/illumination/illumination.go @@ -61,7 +61,6 @@ func BinarySearchIllumination(jdTimeBegin, jdTimeEnd float64, loc *time.Location for it < 50 { mid = low + (high-low)/2.0 illum = GetCurrentMoonIllumination(jt.FromJulianDate(mid, loc), loc) - //log.Printf("Direction: %v, Iteration %d: low=%.6f, high=%.6f, mid=%.6f, illum=%.6f", direction, it, low, high, mid, illum) if math.Abs(illum-0.5) < 0.0001 { return mid } diff --git a/pkg/julian-time/time.go b/pkg/julian-time/time.go index 5361b70..49e90bd 100644 --- a/pkg/julian-time/time.go +++ b/pkg/julian-time/time.go @@ -18,12 +18,10 @@ const ( SecondsPerMinute = 60.0 ) -// looking cool, but mismatch with nasa func ToJulianDate(t time.Time) float64 { year := t.Year() month := int(t.Month()) - // Calculate fractional day including time fractionalDay := (float64(t.Hour()) + float64(t.Minute())/MinutesPerHour + float64(t.Second())/(MinutesPerHour*SecondsPerMinute)) / HoursPerDay @@ -45,32 +43,6 @@ func ToJulianDate(t time.Time) float64 { return jd } -// old -/*func ToJulianDate(t time.Time) float64 { - m := 1 - for i := range months { - if t.Month() == months[i] { - m = i + 1 - } - } - if m < 3 { - t = t.AddDate(-1, 0, 0) - m += 12 - } - - A := float64(t.Year()) / 100 - B := A / 4 - C := 2 - A + B - E := 365.25 * float64(t.Year()+4716) - F := 30.6001 * (float64(m) + 1) - JD := C + float64(float64(t.Day())) + E + F - 1524.5 - - val := float64(t.Hour())/Fhour + float64(t.Minute())/Fminute + float64(t.Second())/Fseconds - JD += val - - return JD - 0.5 -}*/ - func FromJulianDate(j float64, loc *time.Location) time.Time { datey, datem, dated := Jyear(j) timeh, timem, times := Jhms(j) @@ -88,18 +60,15 @@ func SetTimezoneLocFromString(utc string) (*time.Location, error) { re := regexp.MustCompile(`[^a-zA-Z0-9:+-\-]`) utc = re.ReplaceAllString(utc, "") - // Remove "UTC" prefix if present and convert to lowercase for case-insensitive matching normalized := strings.ToLower(utc) normalized = strings.TrimPrefix(normalized, "utc") normalized = strings.TrimPrefix(normalized, "gmt") normalized = strings.TrimSpace(normalized) - // Handle cases like "UTC", "+0", "-0", "0" if normalized == "" || normalized == "+0" || normalized == "-0" || normalized == "0" { return time.UTC, nil } - // Check if it starts with + or - sign := 1 if strings.HasPrefix(normalized, "+") { sign = 1 @@ -112,7 +81,6 @@ func SetTimezoneLocFromString(utc string) (*time.Location, error) { var hours, minutes int var err error - // Handle cases with colon separator (e.g., "05:30", "5:30") if strings.Contains(normalized, ":") { parts := strings.Split(normalized, ":") if len(parts) != 2 { @@ -130,16 +98,15 @@ func SetTimezoneLocFromString(utc string) (*time.Location, error) { } } else { - // Handle cases without colon switch len(normalized) { - case 1, 2: // Just hours (e.g., "5", "12") + case 1, 2: hours, err = strconv.Atoi(normalized) if err != nil { return time.UTC, fmt.Errorf("invalid hours: %s", normalized) } minutes = 0 - case 3: // Hours + minutes (e.g., "530" -> 5 hours, 30 minutes) + case 3: hours, err = strconv.Atoi(normalized[:1]) if err != nil { return time.UTC, fmt.Errorf("invalid hours: %s", normalized[:1]) @@ -149,7 +116,7 @@ func SetTimezoneLocFromString(utc string) (*time.Location, error) { return time.UTC, fmt.Errorf("invalid minutes: %s", normalized[1:]) } - case 4: // Hours + minutes (e.g., "0530" -> 5 hours, 30 minutes) + case 4: hours, err = strconv.Atoi(normalized[:2]) if err != nil { return time.UTC, fmt.Errorf("invalid hours: %s", normalized[:2]) @@ -164,15 +131,12 @@ func SetTimezoneLocFromString(utc string) (*time.Location, error) { } } - // Validate hours range if hours < 0 || hours > 23 { return time.UTC, fmt.Errorf("hours out of range (0-23): %d", hours) } - // Calculate total seconds offset totalSeconds := sign * (hours*3600 + minutes*60) - // Create location name locationName := fmt.Sprintf("UTC%s%d:%02d", m.GetSignPrefix(sign), hours, minutes) if minutes == 0 { locationName = fmt.Sprintf("UTC%s%d", m.GetSignPrefix(sign), hours) @@ -189,23 +153,18 @@ func GetTimeFromLocation(loc *time.Location) (hours int, minutes int, err error) re := regexp.MustCompile(`[^a-zA-Z0-9:+-\-]`) utc = re.ReplaceAllString(utc, "") - // Handle empty string if utc == "" { return 0, 0, errors.New("empty timezone string") } - - // Remove "UTC" prefix if present and convert to lowercase for case-insensitive matching normalized := strings.ToLower(utc) normalized = strings.TrimPrefix(normalized, "utc") normalized = strings.TrimPrefix(normalized, "gmt") normalized = strings.TrimSpace(normalized) - // Handle cases like "+5", "-3", etc. if normalized == "" || normalized == "+0" || normalized == "-0" || normalized == "0" { return 0, 0, nil } - // Check if it starts with + or - var sign int = 1 if strings.HasPrefix(normalized, "+") { sign = 1 @@ -215,7 +174,6 @@ func GetTimeFromLocation(loc *time.Location) (hours int, minutes int, err error) normalized = normalized[1:] } - // Handle cases with colon separator (e.g., "05:30", "5:30") if strings.Contains(normalized, ":") { parts := strings.Split(normalized, ":") if len(parts) != 2 { @@ -235,8 +193,6 @@ func GetTimeFromLocation(loc *time.Location) (hours int, minutes int, err error) return sign * hours, minutes, nil } - // Handle cases without colon (e.g., "0530", "530", "5") - // Check if it's just hours (e.g., "5") if len(normalized) <= 2 { hours, err := strconv.Atoi(normalized) if err != nil { @@ -245,7 +201,6 @@ func GetTimeFromLocation(loc *time.Location) (hours int, minutes int, err error) return sign * hours, minutes, nil } - // Handle cases like "0530" (4 digits) if len(normalized) == 4 { hoursStr := normalized[:2] minutesStr := normalized[2:] @@ -263,7 +218,6 @@ func GetTimeFromLocation(loc *time.Location) (hours int, minutes int, err error) return sign * hours, minutes, nil } - // Handle cases like "530" (3 digits - hours + minutes) if len(normalized) == 3 { hoursStr := normalized[:1] minutesStr := normalized[1:] diff --git a/pkg/moon/days.go b/pkg/moon/days.go index 00bfd72..e9202ae 100644 --- a/pkg/moon/days.go +++ b/pkg/moon/days.go @@ -2,6 +2,7 @@ package moon import ( "math" + "strings" "time" il "moon/pkg/illumination" @@ -9,12 +10,9 @@ import ( phase "moon/pkg/phase" ) -func (c *Cache) CreateMoonTable(timeGiven time.Time) []*MoonTableElement { - t := time.Date(timeGiven.Year(), 0, 0, 0, 0, 0, 0, timeGiven.Location()) - if c.tables != nil && c.tables[t.String()] != nil { - return c.tables[t.String()] - } - moonTable := []*MoonTableElement{} +// to do +func CreateMoonTable(timeGiven time.Time) *MoonTable { + moonTable := new(MoonTable) var l int var k1, mtime float64 @@ -23,7 +21,7 @@ func (c *Cache) CreateMoonTable(timeGiven time.Time) []*MoonTableElement { phaset = make([]float64, 0) - // Tabulate new and full moons surrounding the year + // tabulate new and full moons surrounding the year k1 = math.Floor((float64(timeGiven.Year()) - 1900) * 12.3685) minx = 0 isNext := true @@ -56,16 +54,9 @@ func (c *Cache) CreateMoonTable(timeGiven time.Time) []*MoonTableElement { mp := phaset[l] if mp < 0 { mp = -mp - - elem.t1 = mp - elem.t2 = lastnew - lastnew = mp } - elem.t1 = mp - elem.t2 = lastnew - firstQuarterTime := il.BinarySearchIllumination(lastnew, mp, timeGiven.Location(), true) elem.FirstQuarter = jt.FromJulianDate(firstQuarterTime, timeGiven.Location()) @@ -75,58 +66,134 @@ func (c *Cache) CreateMoonTable(timeGiven time.Time) []*MoonTableElement { elem.NewMoon = jt.FromJulianDate(lastnew, timeGiven.Location()) elem.FullMoon = jt.FromJulianDate(mp, timeGiven.Location()) - if elem.t1 != elem.t2 { - moonTable = append(moonTable, elem) + if mp != lastnew { + moonTable.Elems = append(moonTable.Elems, elem) } if elem.LastQuarter.Year() > timeGiven.Year() { break } } - if c.tables == nil { - c.tables = make(map[string][]*MoonTableElement) - } - if c.tables[t.String()] == nil { - c.tables[t.String()] = moonTable - } + return moonTable } -func BeginMoonDayToEarthDay(tGiven time.Time, duration time.Duration, moonTable []*MoonTableElement) time.Time { +// to do +func BeginMoonDayToEarthDay(tGiven time.Time, duration time.Duration, timeFormat string, moonTable []*MoonTableElement) *any { + var tt any = time.Time{} if len(moonTable) == 0 { - return time.Time{} + return &tt } for i := range moonTable { elem := moonTable[i] - if elem.t1 != elem.t2 { - if tGiven.After(elem.NewMoon) && tGiven.Before(elem.LastQuarter) { - t := elem.NewMoon - t = t.Add(duration) - return t + if tGiven.After(elem.NewMoon) && tGiven.Before(elem.NewMoon.Add(time.Hour*24*32)) { + t := elem.NewMoon.Add(duration) + if strings.ToLower(timeFormat) == "timestamp" { + var tRet any = t.Unix() + return &tRet } - if i < len(moonTable)-1 { - elem2 := moonTable[i+1] - if tGiven.After(elem.LastQuarter) && tGiven.Before(elem2.NewMoon) { - t := elem.NewMoon - t = t.Add(duration) - return t + + if strings.ToLower(timeFormat) != "iso" { + var tRet any = t.Format(timeFormat) + return &tRet + } + + var tRet any = t + return &tRet + } + if i < len(moonTable)-1 { + elem2 := moonTable[i+1] + if tGiven.After(elem.LastQuarter) && tGiven.Before(elem2.NewMoon) { + t := elem.NewMoon.Add(duration) + + if strings.ToLower(timeFormat) == "timestamp" { + var tRet any = t.Unix() + return &tRet } + + if strings.ToLower(timeFormat) != "iso" { + var tRet any = t.Format(timeFormat) + return &tRet + } + + var tRet any = t + return &tRet } } } - return time.Time{} + return &tt } -func GetMoonDays(tGiven time.Time, table []*MoonTableElement) time.Duration { - var moonDays time.Duration +// to do +func FindNearestPhase(tGiven time.Time, moonTable *MoonTable) NearestPhase { + if moonTable == nil { + return NearestPhase{} + } + + var np NearestPhase + + if val, err := SearchPhase(tGiven, moonTable, NewMoon); err == nil { + np.NewMoon = val + } + if val, err := SearchPhase(tGiven, moonTable, FirstQuarter); err == nil { + np.FirstQuarter = val + } + if val, err := SearchPhase(tGiven, moonTable, FullMoon); err == nil { + np.FullMoon = val + } + if val, err := SearchPhase(tGiven, moonTable, LastQuarter); err == nil { + np.LastQuarter = val + } + + return np +} + +func GetMoonDays(tGiven time.Time, table []*MoonTableElement) (MoonDaysInDay, time.Duration) { + tBegin := time.Date(tGiven.Year(), tGiven.Month(), tGiven.Day(), 0, 0, 0, 0, tGiven.Location()) for i := range table { elem := table[i] + if tBegin.After(elem.NewMoon) && tBegin.Before(elem.NewMoon.Add(time.Hour*24*32)) { + var elem2 *MoonTableElement + if i < len(table)-1 { + elem2 = table[i+1] // new next moon + } else { + newTGiven := time.Date(tGiven.Year()+1, time.January, 1, 0, 0, 0, 0, tGiven.Location()) + newT := CreateMoonTable(newTGiven) + if newT != nil && newT.Elems != nil && len(newT.Elems) > 0 { + return GetMoonDays(tGiven, newT.Elems) + } else { + /// return err + } + } + + moonMonDays := elem2.NewMoon.Sub(elem.NewMoon) // moon month + + eartbeg := tBegin.Add(-tGiven.Sub(elem.NewMoon)) + eartend := time.Date(eartbeg.Year(), eartbeg.Month()+1, eartbeg.Day(), eartbeg.Hour(), eartbeg.Minute(), eartbeg.Second(), 0, tBegin.Location()) + eartMon := eartend.Unix() - eartbeg.Unix() // earth month + + beginDay := elem.NewMoon + currentDay := elem.NewMoon + day := time.Hour * time.Duration(int64(moonMonDays.Seconds()/float64(eartMon)*24.)) - if elem.t1 != elem.t2 { - if tGiven.After(elem.NewMoon) /*&& tGiven.Before(elem.TFull)*/ { - moonDays = tGiven.Sub(elem.NewMoon) + for tBegin.Sub(beginDay) > day { + beginDay = beginDay.Add(day) + currentDay = currentDay.Add(day) } + last := tBegin.Sub(beginDay) + beginDay = beginDay.Add(last) + currentDay = currentDay.Add(last) + + currentDay = currentDay.Add(time.Hour * time.Duration(int64(moonMonDays.Seconds()/float64(eartMon)*float64(tGiven.Hour())))) + currentDay = currentDay.Add(time.Minute * time.Duration(int64(moonMonDays.Seconds()/float64(eartMon)*float64(tGiven.Minute())))) + + endDay := beginDay.Add(day) + return MoonDaysInDay{ + Begin: beginDay.Sub(elem.NewMoon) % moonMonDays, + Current: currentDay.Sub(elem.NewMoon) % moonMonDays, + End: endDay.Sub(elem.NewMoon) % moonMonDays, + }, moonMonDays } } - return moonDays + return MoonDaysInDay{time.Duration(0), time.Duration(0), time.Duration(0)}, time.Duration(0) } diff --git a/pkg/moon/models.go b/pkg/moon/models.go index 5b5c562..6c77583 100644 --- a/pkg/moon/models.go +++ b/pkg/moon/models.go @@ -2,27 +2,81 @@ package moon import "time" +type MoonDaysInDay struct { + Begin time.Duration + Current time.Duration + End time.Duration +} + +// used by: +// all moon package +type MoonTable struct { + Elems []*MoonTableElement +} + type MoonTableElement struct { NewMoon time.Time FirstQuarter time.Time FullMoon time.Time LastQuarter time.Time - t1 float64 - t2 float64 } -type Cache struct { - tables map[string][]*MoonTableElement +type EnumPhase int + +const ( + NewMoon EnumPhase = iota + FirstQuarter + FullMoon + LastQuarter +) + +// used by: +// - phase methods +type MoonDaysDetailed struct { + Count int + Day []MoonDay } type MoonDay struct { - Begin *time.Time `json:"Begin,omitempty"` + Begin *any `json:"Begin,omitempty"` IsBeginExists bool - End *time.Time `json:"End,omitempty"` + End *any `json:"End,omitempty"` IsEndExists bool } -type MoonDaysDetailed struct { - Count int - Day []MoonDay +// used by: +// - route-phase +// - rounte-moon-table +type NearestPhase struct { + NewMoon time.Time + FirstQuarter time.Time + FullMoon time.Time + LastQuarter time.Time +} +type NearestPhaseTimestamp struct { + NewMoon int64 + FirstQuarter int64 + FullMoon int64 + LastQuarter int64 +} +type NearestPhaseString struct { + NewMoon string + FirstQuarter string + FullMoon string + LastQuarter string +} + +type SeachMoonDayResp struct { + From time.Time + To time.Time +} + +type SeachMoonDayRespTimestamp struct { + From int64 + To int64 +} + +type SeachMoonDayRespString struct { + From string + To string } diff --git a/pkg/moon/moon.go b/pkg/moon/moon.go index def4dd4..b492a2d 100644 --- a/pkg/moon/moon.go +++ b/pkg/moon/moon.go @@ -1,27 +1,30 @@ package moon import ( + "errors" pos "moon/pkg/position" "time" + + log "github.com/gofiber/fiber/v2/log" ) -func (c *Cache) CurrentMoonDays(tGiven time.Time, loc *time.Location) (time.Duration, time.Duration, time.Duration) { +// to do +func CurrentMoonDays(tGiven time.Time, loc *time.Location, moonTable *MoonTable) MoonDaysInDay { + var mday MoonDaysInDay + if moonTable == nil { + return mday + } + if loc == nil { loc = time.UTC } + currentDayTime := time.Date(tGiven.Year(), tGiven.Month(), tGiven.Day(), tGiven.Hour(), tGiven.Minute(), tGiven.Second(), tGiven.Nanosecond(), loc) - dayBeginTime := time.Date(tGiven.Year(), tGiven.Month(), tGiven.Day(), 0, 0, 0, 0, loc) - dayEndTime := time.Date(tGiven.Year(), tGiven.Month(), tGiven.Day()+1, 0, 0, 0, 0, loc) - - moonTable := c.CreateMoonTable(tGiven) - beginMoonDays := GetMoonDays(dayBeginTime, moonTable) - currentMoonDays := GetMoonDays(tGiven, moonTable) - endMoonDays := GetMoonDays(dayEndTime, moonTable) - - return beginMoonDays, currentMoonDays, endMoonDays + mday, _ = GetMoonDays(currentDayTime, moonTable.Elems) + return mday } -func (c *Cache) MoonDetailed(tGiven time.Time, loc *time.Location, lang string, longitude float64, latitude float64) *MoonDaysDetailed { +func MoonDetailed(tGiven time.Time, loc *time.Location, lang string, timeFormat string, longitude float64, latitude float64) *MoonDaysDetailed { if loc == nil { loc = time.UTC } @@ -34,31 +37,27 @@ func (c *Cache) MoonDetailed(tGiven time.Time, loc *time.Location, lang string, moonDaysDetailed.Day = make([]MoonDay, 2) moonDaysDetailed.Count = 2 - moonRiseYesterday, err1 := pos.GetRisesDay(dayYesterday.Year(), int(dayYesterday.Month()), dayYesterday.Day(), loc, 2, longitude, latitude) - moonRiseToday, err2 := pos.GetRisesDay(dayToday.Year(), int(dayToday.Month()), dayToday.Day(), loc, 2, longitude, latitude) - moonRiseTomorrow, err3 := pos.GetRisesDay(dayTomorrow.Year(), int(dayTomorrow.Month()), dayTomorrow.Day(), loc, 2, longitude, latitude) + moonRiseYesterday, err1 := pos.GetRisesDay(dayYesterday.Year(), int(dayYesterday.Month()), dayYesterday.Day(), loc, 2, timeFormat, longitude, latitude) + moonRiseToday, err2 := pos.GetRisesDay(dayToday.Year(), int(dayToday.Month()), dayToday.Day(), loc, 2, timeFormat, longitude, latitude) + moonRiseTomorrow, err3 := pos.GetRisesDay(dayTomorrow.Year(), int(dayTomorrow.Month()), dayTomorrow.Day(), loc, 2, timeFormat, longitude, latitude) if err1 == nil && err2 == nil { if moonRiseYesterday.IsMoonRise { - moonDaysDetailed.Day[0].Begin = new(time.Time) - *moonDaysDetailed.Day[0].Begin = moonRiseYesterday.Moonrise.TimeISO + moonDaysDetailed.Day[0].Begin = moonRiseYesterday.Moonrise.Time moonDaysDetailed.Day[0].IsBeginExists = true } if moonRiseToday.IsMoonRise { - moonDaysDetailed.Day[0].End = new(time.Time) - *moonDaysDetailed.Day[0].End = moonRiseToday.Moonrise.TimeISO + moonDaysDetailed.Day[0].End = moonRiseToday.Moonrise.Time moonDaysDetailed.Day[0].IsEndExists = true } } if err2 == nil && err3 == nil { if moonRiseToday.IsMoonRise { - moonDaysDetailed.Day[1].Begin = new(time.Time) - *moonDaysDetailed.Day[1].Begin = moonRiseToday.Moonrise.TimeISO + moonDaysDetailed.Day[1].Begin = moonRiseToday.Moonrise.Time moonDaysDetailed.Day[1].IsBeginExists = true } if moonRiseTomorrow.IsMoonRise { - moonDaysDetailed.Day[1].End = new(time.Time) - *moonDaysDetailed.Day[1].End = moonRiseTomorrow.Moonrise.TimeISO + moonDaysDetailed.Day[1].End = moonRiseTomorrow.Moonrise.Time moonDaysDetailed.Day[1].IsEndExists = true } } @@ -70,6 +69,186 @@ func (c *Cache) MoonDetailed(tGiven time.Time, loc *time.Location, lang string, return moonDaysDetailed } -func (c *Cache) GenerateMoonTable(tGiven time.Time) []*MoonTableElement { - return c.CreateMoonTable(tGiven) +func SearchPhase(tGiven time.Time, moonTable *MoonTable, phase EnumPhase) (t time.Time, err error) { + if moonTable == nil { + err = errors.New("passed empty moonTable to SearchNewMoon") + log.Debug(err.Error()) + return + } + err = errors.New("not found") + for i := range moonTable.Elems { + elem := moonTable.Elems[i] + elemSearch1 := elem.NewMoon + if tGiven.Before(elemSearch1) { + elemSearch1 = time.Date(tGiven.Year(), tGiven.Month(), tGiven.Day()-1, 0, 0, 0, 0, tGiven.Location()) + } + elemSearch2 := elem.LastQuarter + + // range current phase: + if tGiven.After(elemSearch1) && tGiven.Before(elemSearch2) { + // found in current phase + switch phase { + case NewMoon: + if tGiven.Before(elem.NewMoon) { + return elem.NewMoon, nil + } + case FirstQuarter: + if tGiven.Before(elem.FirstQuarter) { + return elem.FirstQuarter, nil + } + case FullMoon: + if tGiven.Before(elem.FullMoon) { + return elem.FullMoon, nil + } + case LastQuarter: + if tGiven.Before(elem.LastQuarter) { + return elem.LastQuarter, nil + } + } + // found in next phase + if i < len(moonTable.Elems)-1 { + // use values if in table + switch phase { + case NewMoon: + return moonTable.Elems[i+1].NewMoon, nil + case FirstQuarter: + return moonTable.Elems[i+1].FirstQuarter, nil + case FullMoon: + return moonTable.Elems[i+1].FullMoon, nil + case LastQuarter: + return moonTable.Elems[i+1].LastQuarter, nil + } + } else { + // create table for next table + newT := time.Date(tGiven.Year()+1, 0, 0, 0, 0, 0, 0, tGiven.Location()) + newMoonTable := CreateMoonTable(newT) + + if newMoonTable != nil && newMoonTable.Elems != nil && len(newMoonTable.Elems) > 0 { + switch phase { + case NewMoon: + if tGiven.Before(newMoonTable.Elems[0].NewMoon) { + return newMoonTable.Elems[0].NewMoon, nil + } + case FirstQuarter: + if tGiven.Before(newMoonTable.Elems[0].FirstQuarter) { + return newMoonTable.Elems[0].FirstQuarter, nil + } + case FullMoon: + if tGiven.Before(newMoonTable.Elems[0].FullMoon) { + return newMoonTable.Elems[0].FullMoon, nil + } + case LastQuarter: + if tGiven.Before(newMoonTable.Elems[0].LastQuarter) { + return newMoonTable.Elems[0].LastQuarter, nil + } + } + } + } + } + // range next phase + if i < len(moonTable.Elems)-1 { + // try to find in current table + elem2 := moonTable.Elems[i+1] + elemSearch1 = elem.LastQuarter + + switch phase { + case NewMoon: + elemSearch2 = elem2.NewMoon + case FirstQuarter: + elemSearch2 = elem2.FirstQuarter + case FullMoon: + elemSearch2 = elem2.FullMoon + case LastQuarter: + elemSearch2 = elem2.LastQuarter + } + + if tGiven.After(elemSearch1) && tGiven.Before(elemSearch2) { + return elemSearch2, nil + } + + } else { + // try to find in next table + newT := time.Date(tGiven.Year()+1, 0, 0, 0, 0, 0, 0, tGiven.Location()) + newMoonTable := CreateMoonTable(newT) + if newMoonTable != nil && newMoonTable.Elems != nil && len(newMoonTable.Elems) > 0 { + elemSearch1 = elem.LastQuarter + + switch phase { + case NewMoon: + elemSearch2 = newMoonTable.Elems[0].NewMoon + case FirstQuarter: + elemSearch2 = newMoonTable.Elems[0].FirstQuarter + case FullMoon: + elemSearch2 = newMoonTable.Elems[0].FullMoon + case LastQuarter: + elemSearch2 = newMoonTable.Elems[0].LastQuarter + } + + if tGiven.After(elemSearch1) && tGiven.Before(elemSearch2) { + return elemSearch2, nil + } + } + } + } + return +} + +func SearchMoonDay(tGiven time.Time, moonTable *MoonTable, moonDay int) (SeachMoonDayResp, error) { + t := tGiven + var resp SeachMoonDayResp + var err error + if moonTable == nil { + err = errors.New("passed empty moonTable to SearchNewMoon") + log.Error(err.Error()) + return resp, err + } + err = errors.New("not found") + iters := 0 + for i := range moonTable.Elems { + elem := moonTable.Elems[i] + if t.After(elem.NewMoon) && t.Before(elem.NewMoon.Add(time.Hour*24*32)) { + var elem2 *MoonTableElement + if i < len(moonTable.Elems)-1 { + elem2 = moonTable.Elems[i+1] // new next moon + } else { + newTGiven := time.Date(tGiven.Year()+1, time.January, 1, 0, 0, 0, 0, tGiven.Location()) + newT := CreateMoonTable(newTGiven) + if newT != nil && newT.Elems != nil && len(newT.Elems) > 0 { + return SearchMoonDay(tGiven, newT, moonDay) + } else { + ///// return err + } + } + moonMonDays := elem2.NewMoon.Sub(elem.NewMoon) // moon month + if moonDay > int(moonMonDays) { + break // to do + } + eartbeg := t.Add(-t.Sub(elem.NewMoon)) + eartend := time.Date(eartbeg.Year(), eartbeg.Month()+1, eartbeg.Day(), eartbeg.Hour(), eartbeg.Minute(), eartbeg.Second(), 0, t.Location()) + eartMon := eartend.Unix() - eartbeg.Unix() // earth month + + beginDay := elem.NewMoon + //currentDay := elem.NewMoon + day := time.Hour * time.Duration(int64(moonMonDays.Seconds()/float64(eartMon)*24.)) + //for t.Sub(beginDay) > day { + // beginDay = beginDay.Add(day) + // currentDay = currentDay.Add(day) + //} + log.Debug(beginDay) + beginDay = beginDay.Add(time.Duration(moonDay) * day) + + //currentDay = currentDay.Add(time.Hour * time.Duration(int64(moonMonDays.Seconds()/float64(eartMon)*float64(tGiven.Hour())))) + //currentDay = currentDay.Add(time.Minute * time.Duration(int64(moonMonDays.Seconds()/float64(eartMon)*float64(tGiven.Minute())))) + + endDay := beginDay.Add(day) + + resp.From = beginDay + resp.To = endDay + return resp, nil + } + t = time.Date(t.Year()+1, 0, 0, 0, 0, 0, 0, t.Location()) + moonTable = CreateMoonTable(t) + iters++ + } + return resp, err } diff --git a/pkg/moon/moon_test.go b/pkg/moon/moon_test.go new file mode 100644 index 0000000..715152e --- /dev/null +++ b/pkg/moon/moon_test.go @@ -0,0 +1,647 @@ +package moon + +import ( + "errors" + "testing" + "time" +) + +func TestSearchPhase_NextPhase(t *testing.T) { + location := time.UTC + + tests := []struct { + name string + tGiven time.Time + moonTable *MoonTable + phase EnumPhase + wantTime time.Time + wantError error + }{ + { + name: "nil moon table returns error", + tGiven: time.Now(), + moonTable: nil, + phase: NewMoon, + wantError: errors.New("passed empty moonTable to SearchNewMoon"), + }, + { + name: "empty moon table returns not found", + tGiven: time.Date(2023, 1, 10, 0, 0, 0, 0, location), + moonTable: &MoonTable{ + Elems: []*MoonTableElement{}, + }, + phase: NewMoon, + wantError: errors.New("not found"), + }, + { + name: "next new moon after current time - found in current element", + tGiven: time.Date(2023, 1, 5, 0, 0, 0, 0, location), + moonTable: &MoonTable{ + Elems: []*MoonTableElement{ + { + NewMoon: time.Date(2023, 1, 1, 0, 0, 0, 0, location), + FirstQuarter: time.Date(2023, 1, 8, 0, 0, 0, 0, location), + FullMoon: time.Date(2023, 1, 15, 0, 0, 0, 0, location), + LastQuarter: time.Date(2023, 1, 22, 0, 0, 0, 0, location), + }, + }, + }, + phase: FirstQuarter, + wantTime: time.Date(2023, 1, 8, 0, 0, 0, 0, location), + }, + { + name: "next new moon when current phase already passed - get from next element", + tGiven: time.Date(2023, 1, 10, 0, 0, 0, 0, location), + moonTable: &MoonTable{ + Elems: []*MoonTableElement{ + { + NewMoon: time.Date(2023, 1, 1, 0, 0, 0, 0, location), + FirstQuarter: time.Date(2023, 1, 8, 0, 0, 0, 0, location), + FullMoon: time.Date(2023, 1, 15, 0, 0, 0, 0, location), + LastQuarter: time.Date(2023, 1, 22, 0, 0, 0, 0, location), + }, + { + NewMoon: time.Date(2023, 2, 1, 0, 0, 0, 0, location), + FirstQuarter: time.Date(2023, 2, 8, 0, 0, 0, 0, location), + FullMoon: time.Date(2023, 2, 15, 0, 0, 0, 0, location), + LastQuarter: time.Date(2023, 2, 22, 0, 0, 0, 0, location), + }, + }, + }, + phase: NewMoon, + wantTime: time.Date(2023, 2, 1, 0, 0, 0, 0, location), + }, + { + name: "next full moon between phases - found in next element", + tGiven: time.Date(2023, 1, 25, 0, 0, 0, 0, location), + moonTable: &MoonTable{ + Elems: []*MoonTableElement{ + { + NewMoon: time.Date(2023, 1, 1, 0, 0, 0, 0, location), + FirstQuarter: time.Date(2023, 1, 8, 0, 0, 0, 0, location), + FullMoon: time.Date(2023, 1, 15, 0, 0, 0, 0, location), + LastQuarter: time.Date(2023, 1, 22, 0, 0, 0, 0, location), + }, + { + NewMoon: time.Date(2023, 2, 1, 0, 0, 0, 0, location), + FirstQuarter: time.Date(2023, 2, 8, 0, 0, 0, 0, location), + FullMoon: time.Date(2023, 2, 15, 0, 0, 0, 0, location), + LastQuarter: time.Date(2023, 2, 22, 0, 0, 0, 0, location), + }, + }, + }, + phase: FullMoon, + wantTime: time.Date(2023, 2, 15, 0, 0, 0, 0, location), + }, + { + name: "next phase when time is exactly on phase - should return next occurrence", + tGiven: time.Date(2023, 1, 8, 0, 0, 0, 0, location), + moonTable: &MoonTable{ + Elems: []*MoonTableElement{ + { + NewMoon: time.Date(2023, 1, 1, 0, 0, 0, 0, location), + FirstQuarter: time.Date(2023, 1, 8, 0, 0, 0, 0, location), + FullMoon: time.Date(2023, 1, 15, 0, 0, 0, 0, location), + LastQuarter: time.Date(2023, 1, 22, 0, 0, 0, 0, location), + }, + { + NewMoon: time.Date(2023, 2, 1, 0, 0, 0, 0, location), + FirstQuarter: time.Date(2023, 2, 8, 0, 0, 0, 0, location), + FullMoon: time.Date(2023, 2, 15, 0, 0, 0, 0, location), + LastQuarter: time.Date(2023, 2, 22, 0, 0, 0, 0, location), + }, + }, + }, + phase: FirstQuarter, + wantTime: time.Date(2023, 2, 8, 0, 0, 0, 0, location), + }, + { + name: "time before all phases in table - return first phase", + tGiven: time.Date(2022, 12, 31, 0, 0, 0, 0, location), + moonTable: &MoonTable{ + Elems: []*MoonTableElement{ + { + NewMoon: time.Date(2023, 1, 1, 0, 0, 0, 0, location), + FirstQuarter: time.Date(2023, 1, 8, 0, 0, 0, 0, location), + FullMoon: time.Date(2023, 1, 15, 0, 0, 0, 0, location), + LastQuarter: time.Date(2023, 1, 22, 0, 0, 0, 0, location), + }, + }, + }, + phase: NewMoon, + wantTime: time.Date(2023, 1, 1, 0, 0, 0, 0, location), + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + + gotTime, err := SearchPhase(tt.tGiven, tt.moonTable, tt.phase) + if tt.wantError != nil { + if err == nil { + t.Errorf("Test: %v, SearchPhase() error = %v, wantErr %v", tt.name, err, tt.wantError) + } else if err.Error() != tt.wantError.Error() { + t.Errorf("Test: %v, SearchPhase() error = %v, wantErr %v", tt.name, err, tt.wantError) + } + return + } + + if err != nil { + t.Errorf("Test: %v, SearchPhase() unexpected error = %v", tt.name, err) + return + } + + if !gotTime.Equal(tt.wantTime) { + t.Errorf("Test: %v, SearchPhase() gotTime = %v, want %v", tt.name, gotTime, tt.wantTime) + } + }) + } +} + +func TestSearchPhase_AllPhaseTypes(t *testing.T) { + location := time.UTC + + moonTable := &MoonTable{ + Elems: []*MoonTableElement{ + { + NewMoon: time.Date(2023, 1, 1, 0, 0, 0, 0, location), + FirstQuarter: time.Date(2023, 1, 8, 0, 0, 0, 0, location), + FullMoon: time.Date(2023, 1, 15, 0, 0, 0, 0, location), + LastQuarter: time.Date(2023, 1, 22, 0, 0, 0, 0, location), + }, + { + NewMoon: time.Date(2023, 2, 1, 0, 0, 0, 0, location), + FirstQuarter: time.Date(2023, 2, 8, 0, 0, 0, 0, location), + FullMoon: time.Date(2023, 2, 15, 0, 0, 0, 0, location), + LastQuarter: time.Date(2023, 2, 22, 0, 0, 0, 0, location), + }, + }, + } + + tests := []struct { + name string + tGiven time.Time + phase EnumPhase + wantTime time.Time + }{ + { + name: "next new moon", + tGiven: time.Date(2023, 1, 5, 0, 0, 0, 0, location), + phase: NewMoon, + wantTime: time.Date(2023, 2, 1, 0, 0, 0, 0, location), + }, + { + name: "next first quarter", + tGiven: time.Date(2023, 1, 5, 0, 0, 0, 0, location), + phase: FirstQuarter, + wantTime: time.Date(2023, 1, 8, 0, 0, 0, 0, location), + }, + { + name: "next full moon", + tGiven: time.Date(2023, 1, 10, 0, 0, 0, 0, location), + phase: FullMoon, + wantTime: time.Date(2023, 1, 15, 0, 0, 0, 0, location), + }, + { + name: "next last quarter", + tGiven: time.Date(2023, 1, 20, 0, 0, 0, 0, location), + phase: LastQuarter, + wantTime: time.Date(2023, 1, 22, 0, 0, 0, 0, location), + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result, err := SearchPhase(tt.tGiven, moonTable, tt.phase) + + if err != nil { + t.Errorf("SearchPhase() for %s failed with error: %v", tt.name, err) + return + } + + if !result.Equal(tt.wantTime) { + t.Errorf("SearchPhase() for %s gotTime = %v, want %v", tt.name, result, tt.wantTime) + } + }) + } +} + +func TestSearchPhase_ComplexScenarios(t *testing.T) { + location := time.UTC + + tests := []struct { + name string + tGiven time.Time + moonTable *MoonTable + phase EnumPhase + wantTime time.Time + }{ + { + name: "multiple elements - find in third element", + tGiven: time.Date(2023, 3, 1, 0, 0, 0, 0, location), + moonTable: &MoonTable{ + Elems: []*MoonTableElement{ + { + NewMoon: time.Date(2023, 1, 1, 0, 0, 0, 0, location), + FirstQuarter: time.Date(2023, 1, 8, 0, 0, 0, 0, location), + FullMoon: time.Date(2023, 1, 15, 0, 0, 0, 0, location), + LastQuarter: time.Date(2023, 1, 22, 0, 0, 0, 0, location), + }, + { + NewMoon: time.Date(2023, 2, 1, 0, 0, 0, 0, location), + FirstQuarter: time.Date(2023, 2, 8, 0, 0, 0, 0, location), + FullMoon: time.Date(2023, 2, 15, 0, 0, 0, 0, location), + LastQuarter: time.Date(2023, 2, 22, 0, 0, 0, 0, location), + }, + { + NewMoon: time.Date(2023, 3, 3, 0, 0, 0, 0, location), + FirstQuarter: time.Date(2023, 3, 10, 0, 0, 0, 0, location), + FullMoon: time.Date(2023, 3, 17, 0, 0, 0, 0, location), + LastQuarter: time.Date(2023, 3, 24, 0, 0, 0, 0, location), + }, + }, + }, + phase: FirstQuarter, + wantTime: time.Date(2023, 3, 10, 0, 0, 0, 0, location), + }, + { + name: "phase in gap between elements", + tGiven: time.Date(2023, 1, 25, 0, 0, 0, 0, location), + moonTable: &MoonTable{ + Elems: []*MoonTableElement{ + { + NewMoon: time.Date(2023, 1, 1, 0, 0, 0, 0, location), + FirstQuarter: time.Date(2023, 1, 8, 0, 0, 0, 0, location), + FullMoon: time.Date(2023, 1, 15, 0, 0, 0, 0, location), + LastQuarter: time.Date(2023, 1, 22, 0, 0, 0, 0, location), + }, + { + NewMoon: time.Date(2023, 2, 1, 0, 0, 0, 0, location), + FirstQuarter: time.Date(2023, 2, 8, 0, 0, 0, 0, location), + FullMoon: time.Date(2023, 2, 15, 0, 0, 0, 0, location), + LastQuarter: time.Date(2023, 2, 22, 0, 0, 0, 0, location), + }, + }, + }, + phase: NewMoon, + wantTime: time.Date(2023, 2, 1, 0, 0, 0, 0, location), + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result, err := SearchPhase(tt.tGiven, tt.moonTable, tt.phase) + + if err != nil { + t.Errorf("SearchPhase() for %s failed with error: %v", tt.name, err) + return + } + + if !result.Equal(tt.wantTime) { + t.Errorf("SearchPhase() for %s gotTime = %v, want %v", tt.name, result, tt.wantTime) + } + }) + } +} + +func TestSearchPhase_EdgeCases(t *testing.T) { + location := time.UTC + + tests := []struct { + name string + tGiven time.Time + moonTable *MoonTable + phase EnumPhase + wantTime time.Time + wantError error + }{ + { + name: "time exactly at last quarter - should return next phase from next element", + tGiven: time.Date(2023, 1, 22, 0, 0, 0, 0, location), + moonTable: &MoonTable{ + Elems: []*MoonTableElement{ + { + NewMoon: time.Date(2023, 1, 1, 0, 0, 0, 0, location), + FirstQuarter: time.Date(2023, 1, 8, 0, 0, 0, 0, location), + FullMoon: time.Date(2023, 1, 15, 0, 0, 0, 0, location), + LastQuarter: time.Date(2023, 1, 22, 0, 0, 0, 0, location), + }, + { + NewMoon: time.Date(2023, 2, 1, 0, 0, 0, 0, location), + FirstQuarter: time.Date(2023, 2, 8, 0, 0, 0, 0, location), + FullMoon: time.Date(2023, 2, 15, 0, 0, 0, 0, location), + LastQuarter: time.Date(2023, 2, 22, 0, 0, 0, 0, location), + }, + }, + }, + phase: LastQuarter, + wantTime: time.Date(2023, 2, 22, 0, 0, 0, 0, location), + }, + { + name: "time between last quarter and next new moon - should return next new moon", + tGiven: time.Date(2023, 1, 25, 0, 0, 0, 0, location), + moonTable: &MoonTable{ + Elems: []*MoonTableElement{ + { + NewMoon: time.Date(2023, 1, 1, 0, 0, 0, 0, location), + FirstQuarter: time.Date(2023, 1, 8, 0, 0, 0, 0, location), + FullMoon: time.Date(2023, 1, 15, 0, 0, 0, 0, location), + LastQuarter: time.Date(2023, 1, 22, 0, 0, 0, 0, location), + }, + { + NewMoon: time.Date(2023, 2, 1, 0, 0, 0, 0, location), + FirstQuarter: time.Date(2023, 2, 8, 0, 0, 0, 0, location), + FullMoon: time.Date(2023, 2, 15, 0, 0, 0, 0, location), + LastQuarter: time.Date(2023, 2, 22, 0, 0, 0, 0, location), + }, + }, + }, + phase: NewMoon, + wantTime: time.Date(2023, 2, 1, 0, 0, 0, 0, location), + }, + { + name: "mixed valid and invalid elements", + tGiven: time.Date(2023, 1, 10, 0, 0, 0, 0, location), + moonTable: &MoonTable{ + Elems: []*MoonTableElement{ + { + NewMoon: time.Date(2023, 1, 1, 0, 0, 0, 0, location), + FirstQuarter: time.Date(2023, 1, 8, 0, 0, 0, 0, location), + FullMoon: time.Date(2023, 1, 15, 0, 0, 0, 0, location), + LastQuarter: time.Date(2023, 1, 22, 0, 0, 0, 0, location), + }, + { + NewMoon: time.Date(2023, 2, 1, 0, 0, 0, 0, location), + FirstQuarter: time.Date(2023, 2, 8, 0, 0, 0, 0, location), + FullMoon: time.Date(2023, 2, 15, 0, 0, 0, 0, location), + LastQuarter: time.Date(2023, 2, 22, 0, 0, 0, 0, location), + }, + }, + }, + phase: NewMoon, + wantTime: time.Date(2023, 2, 1, 0, 0, 0, 0, location), + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + gotTime, err := SearchPhase(tt.tGiven, tt.moonTable, tt.phase) + + if tt.wantError != nil { + if err == nil { + t.Errorf("Test: %v, SearchPhase() error = %v, wantErr %v", tt.name, err, tt.wantError) + } else if err.Error() != tt.wantError.Error() { + t.Errorf("Test: %v, SearchPhase() error = %v, wantErr %v", tt.name, err, tt.wantError) + } + return + } + + if err != nil { + t.Errorf("Test: %v, SearchPhase() unexpected error = %v", tt.name, err) + return + } + + if !gotTime.Equal(tt.wantTime) { + t.Errorf("Test: %v, SearchPhase() gotTime = %v, want %v", tt.name, gotTime, tt.wantTime) + } + }) + } +} + +func TestSearchPhase_TimeLocation(t *testing.T) { + utcLocation := time.UTC + moscowLocation, _ := time.LoadLocation("Europe/Moscow") + newYorkLocation, _ := time.LoadLocation("America/New_York") + + tests := []struct { + name string + tGiven time.Time + moonTable *MoonTable + phase EnumPhase + wantTime time.Time + }{ + { + name: "Moscow timezone", + tGiven: time.Date(2023, 1, 5, 0, 0, 0, 0, moscowLocation), + moonTable: &MoonTable{ + Elems: []*MoonTableElement{ + { + NewMoon: time.Date(2023, 1, 1, 0, 0, 0, 0, moscowLocation), + FirstQuarter: time.Date(2023, 1, 8, 0, 0, 0, 0, moscowLocation), + FullMoon: time.Date(2023, 1, 15, 0, 0, 0, 0, moscowLocation), + LastQuarter: time.Date(2023, 1, 22, 0, 0, 0, 0, moscowLocation), + }, + }, + }, + phase: FirstQuarter, + wantTime: time.Date(2023, 1, 8, 0, 0, 0, 0, moscowLocation), + }, + { + name: "New York timezone", + tGiven: time.Date(2023, 1, 5, 0, 0, 0, 0, newYorkLocation), + moonTable: &MoonTable{ + Elems: []*MoonTableElement{ + { + NewMoon: time.Date(2023, 1, 1, 0, 0, 0, 0, newYorkLocation), + FirstQuarter: time.Date(2023, 1, 8, 0, 0, 0, 0, newYorkLocation), + FullMoon: time.Date(2023, 1, 15, 0, 0, 0, 0, newYorkLocation), + LastQuarter: time.Date(2023, 1, 22, 0, 0, 0, 0, newYorkLocation), + }, + }, + }, + phase: FirstQuarter, + wantTime: time.Date(2023, 1, 8, 0, 0, 0, 0, newYorkLocation), + }, + { + name: "mixed timezones - should handle correctly", + tGiven: time.Date(2023, 1, 5, 0, 0, 0, 0, moscowLocation), + moonTable: &MoonTable{ + Elems: []*MoonTableElement{ + { + NewMoon: time.Date(2023, 1, 1, 0, 0, 0, 0, utcLocation), + FirstQuarter: time.Date(2023, 1, 8, 0, 0, 0, 0, utcLocation), + FullMoon: time.Date(2023, 1, 15, 0, 0, 0, 0, utcLocation), + LastQuarter: time.Date(2023, 1, 22, 0, 0, 0, 0, utcLocation), + }, + }, + }, + phase: FirstQuarter, + wantTime: time.Date(2023, 1, 8, 0, 0, 0, 0, utcLocation), + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result, err := SearchPhase(tt.tGiven, tt.moonTable, tt.phase) + + if err != nil { + t.Errorf("SearchPhase() for %s failed with error: %v", tt.name, err) + return + } + + if !result.Equal(tt.wantTime) { + t.Errorf("SearchPhase() for %s gotTime = %v, want %v", tt.name, result, tt.wantTime) + } + + if result.Location() != tt.wantTime.Location() { + t.Errorf("SearchPhase() for %s location = %v, want %v", + tt.name, result.Location(), tt.wantTime.Location()) + } + }) + } +} + +func TestSearchPhase_PhaseOrder(t *testing.T) { + location := time.UTC + + moonTable := &MoonTable{ + Elems: []*MoonTableElement{ + { + NewMoon: time.Date(2023, 1, 1, 0, 0, 0, 0, location), + FirstQuarter: time.Date(2023, 1, 8, 0, 0, 0, 0, location), + FullMoon: time.Date(2023, 1, 15, 0, 0, 0, 0, location), + LastQuarter: time.Date(2023, 1, 22, 0, 0, 0, 0, location), + }, + }, + } + + tests := []struct { + name string + tGiven time.Time + phase EnumPhase + wantTime time.Time + desc string + }{ + { + name: "between new moon and first quarter - find first quarter", + tGiven: time.Date(2023, 1, 3, 0, 0, 0, 0, location), + phase: FirstQuarter, + wantTime: time.Date(2023, 1, 8, 0, 0, 0, 0, location), + }, + { + name: "between first quarter and full moon - find full moon", + tGiven: time.Date(2023, 1, 10, 0, 0, 0, 0, location), + phase: FullMoon, + wantTime: time.Date(2023, 1, 15, 0, 0, 0, 0, location), + }, + { + name: "between full moon and last quarter - find last quarter", + tGiven: time.Date(2023, 1, 18, 0, 0, 0, 0, location), + phase: LastQuarter, + wantTime: time.Date(2023, 1, 22, 0, 0, 0, 0, location), + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result, err := SearchPhase(tt.tGiven, moonTable, tt.phase) + + if err != nil { + t.Errorf("SearchPhase() for %s failed with error: %v", tt.name, err) + return + } + + if !result.Equal(tt.wantTime) { + t.Errorf("SearchPhase() for %s gotTime = %v, want %v. %s", + tt.name, result, tt.wantTime, tt.desc) + } + }) + } +} + +func TestSearchPhase_SingleElement(t *testing.T) { + location := time.UTC + + singleElementTable := &MoonTable{ + Elems: []*MoonTableElement{ + { + NewMoon: time.Date(2023, 1, 1, 0, 0, 0, 0, location), + FirstQuarter: time.Date(2023, 1, 8, 0, 0, 0, 0, location), + FullMoon: time.Date(2023, 1, 15, 0, 0, 0, 0, location), + LastQuarter: time.Date(2023, 1, 22, 0, 0, 0, 0, location), + }, + }, + } + + tests := []struct { + name string + tGiven time.Time + phase EnumPhase + wantTime time.Time + wantError error + }{ + { + name: "before all phases - return first phase", + tGiven: time.Date(2022, 12, 31, 0, 0, 0, 0, location), + phase: NewMoon, + wantTime: time.Date(2023, 1, 1, 0, 0, 0, 0, location), + }, + { + name: "after all phases - should try to create next table", + tGiven: time.Date(2023, 12, 31, 0, 0, 0, 0, location), + phase: NewMoon, + wantError: errors.New("not found"), + }, + { + name: "exactly in middle - find next phase", + tGiven: time.Date(2023, 1, 10, 0, 0, 0, 0, location), + phase: FullMoon, + wantTime: time.Date(2023, 1, 15, 0, 0, 0, 0, location), + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result, err := SearchPhase(tt.tGiven, singleElementTable, tt.phase) + + if tt.wantError != nil { + if err == nil { + t.Errorf("Test: %v, SearchPhase() error = %v, wantErr %v", tt.name, err, tt.wantError) + } else if err.Error() != tt.wantError.Error() { + t.Errorf("Test: %v, SearchPhase() error = %v, wantErr %v", tt.name, err, tt.wantError) + } + return + } + + if err != nil { + t.Errorf("Test: %v, SearchPhase() unexpected error = %v", tt.name, err) + return + } + + if !result.Equal(tt.wantTime) { + t.Errorf("Test: %v, SearchPhase() gotTime = %v, want %v", tt.name, result, tt.wantTime) + } + }) + } +} + +func TestSearchPhase_Performance(t *testing.T) { + location := time.UTC + + var elems []*MoonTableElement + for i := 0; i < 100; i++ { + baseTime := time.Date(2023, time.Month(i+1), 1, 0, 0, 0, 0, location) + elem := &MoonTableElement{ + NewMoon: baseTime, + FirstQuarter: baseTime.AddDate(0, 0, 7), + FullMoon: baseTime.AddDate(0, 0, 14), + LastQuarter: baseTime.AddDate(0, 0, 21), + } + elems = append(elems, elem) + } + + largeMoonTable := &MoonTable{Elems: elems} + + tGiven := time.Date(2023, 6, 15, 0, 0, 0, 0, location) + result, err := SearchPhase(tGiven, largeMoonTable, FullMoon) + + if err != nil { + t.Errorf("SearchPhase() with large table failed: %v", err) + return + } + + expected := time.Date(2023, 7, 15, 0, 0, 0, 0, location) + if !result.Equal(expected) { + t.Errorf("SearchPhase() with large table gotTime = %v, want %v", result, expected) + } +} diff --git a/pkg/phase/models.go b/pkg/phase/models.go index 9e41a55..e1d4288 100644 --- a/pkg/phase/models.go +++ b/pkg/phase/models.go @@ -1,8 +1,21 @@ package phase type PhaseResp struct { + BeginDay *Phase + Current *Phase + EndDay *Phase + Illumination Illumination +} + +type Phase struct { Name string NameLocalized string Emoji string IsWaxing bool } + +type Illumination struct { + BeginDay float64 + Current float64 + EndDay float64 +} diff --git a/pkg/phase/phase.go b/pkg/phase/phase.go index 23a57d6..f2d26f2 100644 --- a/pkg/phase/phase.go +++ b/pkg/phase/phase.go @@ -9,7 +9,8 @@ import ( type illumFunc func(tGiven time.Time, loc *time.Location) float64 -func CurrentMoonPhase(tGiven time.Time, lang string) (float64, float64, float64, PhaseResp, PhaseResp, PhaseResp) { +func CurrentMoonPhase(tGiven time.Time, lang string) *PhaseResp { + pr := new(PhaseResp) newT := time.Date(tGiven.Year(), tGiven.Month(), tGiven.Day(), tGiven.Hour(), tGiven.Minute(), tGiven.Second(), 0, time.UTC) currentMoonIllumination, currentMoonIlluminationBefore, currentMoonIlluminationAfter := currentMoonPhaseCalc(newT, time.FixedZone("UTC+12", -12*60*60), il.GetCurrentMoonIllumination) @@ -38,10 +39,18 @@ func CurrentMoonPhase(tGiven time.Time, lang string) (float64, float64, float64, moonPhaseEnd.IsWaxing = false } - return currentMoonIllumination, dayBeginMoonIllumination, dayEndMoonIllumination, moonPhaseCurrent, moonPhaseBegin, moonPhaseEnd + pr.BeginDay = &moonPhaseBegin + pr.Current = &moonPhaseCurrent + pr.EndDay = &moonPhaseEnd + + pr.Illumination.BeginDay = dayBeginMoonIllumination + pr.Illumination.Current = currentMoonIllumination + pr.Illumination.EndDay = dayEndMoonIllumination + + return pr } -func GetMoonPhase(before, current, after float64, lang string) PhaseResp { +func GetMoonPhase(before, current, after float64, lang string) Phase { phaseName, phangeNameLocalized, phaseEmoji := "", "", "" switch { case current > 0.05 && current < 0.45 && current < after: @@ -69,7 +78,7 @@ func GetMoonPhase(before, current, after float64, lang string) PhaseResp { phangeNameLocalized = getMoonPhasesLocalized(lang, 7) phaseName, phaseEmoji = getMoonPhases(7) } - return PhaseResp{Name: phaseName, NameLocalized: phangeNameLocalized, Emoji: phaseEmoji} + return Phase{Name: phaseName, NameLocalized: phangeNameLocalized, Emoji: phaseEmoji} } func getMoonPhases(position int) (string, string) { @@ -113,6 +122,7 @@ func currentMoonPhaseCalc(tGiven time.Time, loc *time.Location, calcF illumFunc) func Truephase(k, phase float64) float64 { var t, t2, t3, pt, m, mprime, f float64 + // to do SynMonth := 29.53058868 // Synodic month (mean time from new to next new Moon) k += phase // Add phase to new moon time diff --git a/pkg/position/position.go b/pkg/position/position.go index 6f630f5..09eaf47 100644 --- a/pkg/position/position.go +++ b/pkg/position/position.go @@ -8,9 +8,16 @@ import ( jt "moon/pkg/julian-time" "net/http" "net/url" + "strconv" + "strings" "time" ) +type Cache struct { + CacheDaily map[string]*DayData + CacheMonthly map[string]*[]DayData +} + // DayResponse type DayResponse struct { Status string `json:"Status"` @@ -22,6 +29,7 @@ type DayResponse struct { // MonthResponse type MonthResponse struct { Status string `json:"Status"` + Message string `json:"Message,omitempty"` Parameters Parameters `json:"Parameters"` Data []DayData `json:"Data"` Range string `json:"Range"` @@ -41,29 +49,57 @@ type Parameters struct { // resp for 1 day type MoonPosition struct { - Timestamp int64 `json:"Timestamp"` - TimeISO time.Time `json:"TimeISO,omitempty"` - AzimuthDegrees float64 `json:"AzimuthDegrees"` - AltitudeDegrees float64 `json:"AltitudeDegrees"` - Direction string `json:"Direction"` - DistanceKm float64 `json:"DistanceKm"` + Timestamp *int64 `json:"Timestamp,omitempty"` + Time *any `json:"Time"` + AzimuthDegrees float64 `json:"AzimuthDegrees"` + AltitudeDegrees float64 `json:"AltitudeDegrees"` + Direction string `json:"Direction"` + DistanceKm float64 `json:"DistanceKm"` } type DayData struct { - Moonrise *MoonPosition `json:"Moonrise,omitempty"` - Moonset *MoonPosition `json:"Moonset,omitempty"` - Meridian *MoonPosition `json:"Meridian,omitempty"` + Day *string `json:"Date,omitempty"` IsMoonRise bool `json:"IsMoonRise"` IsMoonSet bool `json:"IsMoonSet"` IsMeridian bool `json:"IsMeridian"` + Moonrise *MoonPosition `json:"Moonrise,omitempty"` + Moonset *MoonPosition `json:"Moonset,omitempty"` + Meridian *MoonPosition `json:"Meridian,omitempty"` } -func GetRisesMonthly(year, month int, loc *time.Location, precision int, location ...float64) (*MonthResponse, error) { +func (c *Cache) GetRisesMonthly(year, month int, loc *time.Location, precision int, timeFormat string, location ...float64) (*[]DayData, error) { lat, lon, err := parseLocation(location) if err != nil { return nil, err } + if c.CacheMonthly == nil { + c.CacheMonthly = make(map[string]*[]DayData) + } + + var strKey strings.Builder + strKey.WriteString(strconv.Itoa(year)) + strKey.WriteString("-") + strKey.WriteString(strconv.Itoa(month)) + strKey.WriteString("-") + if loc != nil { + strKey.WriteString(loc.String()) + } else { + strKey.WriteString("nil") + } + strKey.WriteString("-") + strKey.WriteString(strconv.Itoa(precision)) + strKey.WriteString("-") + strKey.WriteString(strconv.FormatFloat(lat, 'e', precision, 64)) + strKey.WriteString("-") + strKey.WriteString(strconv.FormatFloat(lon, 'e', precision, 64)) + strKey.WriteString("-") + strKey.WriteString(timeFormat) + + if c.CacheMonthly != nil && c.CacheMonthly[strKey.String()] != nil { + return c.CacheMonthly[strKey.String()], nil + } + h := 0 if loc != nil { jth, _, err := jt.GetTimeFromLocation(loc) @@ -80,32 +116,56 @@ func GetRisesMonthly(year, month int, loc *time.Location, precision int, locatio params.Add("month", fmt.Sprintf("%d", month)) params.Add("precision", fmt.Sprintf("%d", precision)) - url := baseURL + "?" + params.Encode() + url := baseURL + "monthly?" + params.Encode() client := &http.Client{Timeout: 69 * time.Second} resp, err := client.Get(url) if err != nil { - return nil, fmt.Errorf("failed to make request: %w", err) + return nil, fmt.Errorf("[%s] Failed to make request: %w", resp.Status, err) } defer resp.Body.Close() - if resp.StatusCode != http.StatusOK { - return nil, fmt.Errorf("server returned status: %s", resp.Status) - } - body, err := io.ReadAll(resp.Body) if err != nil { - return nil, fmt.Errorf("failed to read response: %w", err) + return nil, fmt.Errorf("[%s] Failed to read response: %w", resp.Status, err) } var monthResponse MonthResponse if err := json.Unmarshal(body, &monthResponse); err != nil { - return nil, fmt.Errorf("failed to unmarshal response: %w", err) + return nil, fmt.Errorf("[%s] Failed to unmarshal response: %w", resp.Status, err) + } + + if resp.StatusCode != http.StatusOK { + return nil, fmt.Errorf("[%s] %s", resp.Status, monthResponse.Message) + } + + for i := range monthResponse.Data { + if monthResponse.Data[i].Meridian != nil && monthResponse.Data[i].Meridian.Timestamp != nil { + var t any = timestampToGoTime(monthResponse.Data[i].Meridian.Timestamp, timeFormat, loc) + monthResponse.Data[i].Meridian.Time = &t + monthResponse.Data[i].Meridian.Timestamp = nil + } + if monthResponse.Data[i].Moonrise != nil && monthResponse.Data[i].Moonrise.Timestamp != nil { + var t any = timestampToGoTime(monthResponse.Data[i].Moonrise.Timestamp, timeFormat, loc) + monthResponse.Data[i].Moonrise.Time = &t + monthResponse.Data[i].Moonrise.Timestamp = nil + } + if monthResponse.Data[i].Moonset != nil { + var t any = timestampToGoTime(monthResponse.Data[i].Moonset.Timestamp, timeFormat, loc) + monthResponse.Data[i].Moonset.Time = &t + monthResponse.Data[i].Moonset.Timestamp = nil + } + t := time.Date(year, jt.GetMonth(month), 1+i, 0, 0, 0, 0, time.UTC).Format("2006-01-02") + monthResponse.Data[i].Day = &t + } + + if c.CacheMonthly != nil && c.CacheMonthly[strKey.String()] == nil { + c.CacheMonthly[strKey.String()] = &monthResponse.Data } - return &monthResponse, nil + return &monthResponse.Data, nil } -func GetRisesDay(year, month, day int, loc *time.Location, precision int, location ...float64) (*DayData, error) { +func GetRisesDay(year, month, day int, loc *time.Location, precision int, timeFormat string, location ...float64) (*DayData, error) { lat, lon, err := parseLocation(location) if err != nil { return nil, err @@ -151,23 +211,75 @@ func GetRisesDay(year, month, day int, loc *time.Location, precision int, locati if err := json.Unmarshal(body, &dayResponse); err != nil { return nil, fmt.Errorf("failed to unmarshal response: %w", err) } - if dayResponse.Data.Meridian != nil { - timestampToGoTime(dayResponse.Data.Meridian, loc) - dayResponse.Data.Meridian.Timestamp = dayResponse.Data.Meridian.TimeISO.Unix() + if dayResponse.Data.Meridian != nil && dayResponse.Data.Meridian.Timestamp != nil { + var t any = timestampToGoTime(dayResponse.Data.Meridian.Timestamp, timeFormat, loc) + dayResponse.Data.Meridian.Time = &t + dayResponse.Data.Meridian.Timestamp = nil } - if dayResponse.Data.Moonrise != nil { - timestampToGoTime(dayResponse.Data.Moonrise, loc) - dayResponse.Data.Moonrise.Timestamp = dayResponse.Data.Moonrise.TimeISO.Unix() + if dayResponse.Data.Moonrise != nil && dayResponse.Data.Moonrise.Timestamp != nil { + var t any = timestampToGoTime(dayResponse.Data.Moonrise.Timestamp, timeFormat, loc) + dayResponse.Data.Moonrise.Time = &t + dayResponse.Data.Moonrise.Timestamp = nil } if dayResponse.Data.Moonset != nil { - timestampToGoTime(dayResponse.Data.Moonset, loc) - dayResponse.Data.Moonset.Timestamp = dayResponse.Data.Moonset.TimeISO.Unix() + var t any = timestampToGoTime(dayResponse.Data.Moonset.Timestamp, timeFormat, loc) + dayResponse.Data.Moonset.Time = &t + dayResponse.Data.Moonset.Timestamp = nil } return dayResponse.Data, nil } -func GetMoonPosition(tGiven time.Time, loc *time.Location, precision int, location ...float64) (*MoonPosition, error) { +func (c *Cache) GetRisesDay(year, month, day int, loc *time.Location, precision int, timeFormat string, location ...float64) (*DayData, error) { + lat, lon, err := parseLocation(location) + if err != nil { + return nil, err + } + + if c.CacheDaily == nil { + c.CacheDaily = make(map[string]*DayData) + } + + var strKey strings.Builder + strKey.WriteString(strconv.Itoa(year)) + strKey.WriteString("-") + strKey.WriteString(strconv.Itoa(month)) + strKey.WriteString("-") + strKey.WriteString(strconv.Itoa(day)) + strKey.WriteString("-") + if loc != nil { + strKey.WriteString(loc.String()) + } else { + strKey.WriteString("nil") + } + strKey.WriteString("-") + strKey.WriteString(strconv.Itoa(precision)) + strKey.WriteString("-") + strKey.WriteString(strconv.FormatFloat(lat, 'e', precision, 64)) + strKey.WriteString("-") + strKey.WriteString(strconv.FormatFloat(lon, 'e', precision, 64)) + strKey.WriteString("-") + strKey.WriteString(timeFormat) + + if c.CacheDaily != nil && c.CacheDaily[strKey.String()] != nil { + return c.CacheDaily[strKey.String()], nil + } + + dayResponse, err := GetRisesDay(year, month, day, loc, precision, timeFormat, location...) + if err != nil { + return nil, err + } + + if c.CacheDaily != nil && c.CacheDaily[strKey.String()] == nil { + c.CacheDaily[strKey.String()] = dayResponse + } + + return dayResponse, nil +} + +// to do: refactor here. +// 3 req to 1 day is not ok +func GetMoonPosition(tGiven time.Time, loc *time.Location, precision int, timeFormat string, location ...float64) (*MoonPosition, error) { lat, lon, err := parseLocation(location) if err != nil { return nil, err @@ -217,8 +329,10 @@ func GetMoonPosition(tGiven time.Time, loc *time.Location, precision int, locati if err := json.Unmarshal(body, &pos); err != nil { return nil, fmt.Errorf("failed to unmarshal response: %w", err) } - if pos != nil { - timestampToGoTime(pos, loc) + if pos != nil && pos.Timestamp != nil { + var t any = timestampToGoTime(pos.Timestamp, timeFormat, loc) + pos.Time = &t + pos.Timestamp = nil } return pos, nil @@ -235,10 +349,26 @@ func parseLocation(location []float64) (lat, lon float64, err error) { return lat, lon, nil } -func timestampToGoTime(ev *MoonPosition, loc *time.Location) { - utcTime := time.Unix(ev.Timestamp, 0).UTC() - ev.TimeISO = utcTime +func timestampToGoTime(ev *int64, timeFormat string, loc *time.Location) *any { + if ev == nil { + return nil + } + utcTime := time.Unix(*ev, 0).UTC() + time := utcTime if loc != nil { - ev.TimeISO = ev.TimeISO.In(loc) + time = time.In(loc) + } + + if strings.ToLower(timeFormat) == "timestamp" { + var t any = time.Unix() + return &t } + + if strings.ToLower(timeFormat) != "iso" { + var t any = time.Format(timeFormat) + return &t + } + + var t any = time + return &t } diff --git a/pkg/zodiac/models.go b/pkg/zodiac/models.go index 9eaee83..bac5dec 100644 --- a/pkg/zodiac/models.go +++ b/pkg/zodiac/models.go @@ -1,13 +1,11 @@ package zodiac -import "time" - type ZodiacDetailed struct { Name string NameLocalized string Emoji string - Begin time.Time - End time.Time + Begin *any + End *any } type Zodiacs struct { diff --git a/pkg/zodiac/zodiac.go b/pkg/zodiac/zodiac.go index 55e373e..421b3ad 100644 --- a/pkg/zodiac/zodiac.go +++ b/pkg/zodiac/zodiac.go @@ -6,33 +6,31 @@ import ( "time" ) -func CurrentZodiacs(tGiven time.Time, loc *time.Location, lang string, moonTable []*moon.MoonTableElement) (*Zodiacs, Zodiac, Zodiac, Zodiac) { +func CurrentZodiacs(tGiven time.Time, loc *time.Location, lang string, timeFormat string, moonTable []*moon.MoonTableElement) (*Zodiacs, Zodiac, Zodiac, Zodiac) { zods := new(Zodiacs) zodiacBegin := Zodiac{} zodiacCurrent := Zodiac{} zodiacEnd := Zodiac{} - dayBeginTime := time.Date(tGiven.Year(), tGiven.Month(), tGiven.Day(), 0, 0, 0, 0, loc) - dayEndTime := time.Date(tGiven.Year(), tGiven.Month(), tGiven.Day()+1, 0, 0, 0, 0, loc) + var day moon.MoonDaysInDay - beginMoonDays := moon.GetMoonDays(dayBeginTime, moonTable) - currentMoonDays := moon.GetMoonDays(tGiven, moonTable) - endMoonDays := moon.GetMoonDays(dayEndTime, moonTable) + dayBeginTime := time.Date(tGiven.Year(), tGiven.Month(), tGiven.Day(), 0, 0, 0, 0, loc) + day, _ = moon.GetMoonDays(dayBeginTime, moonTable) - zodiacPositionBegin := int((beginMoonDays.Minutes()/jt.Fminute*360.)/30./30.) % 12 - zodiacPositionCurrent := int((currentMoonDays.Minutes()/jt.Fminute*360.)/30./30.) % 12 - zodiacPositionEnd := int((endMoonDays.Minutes()/jt.Fminute*360.)/30./30.) % 12 + zodiacPositionBegin := int((day.Begin.Minutes()/jt.Fminute*360.)/30./30.) % 12 + zodiacPositionCurrent := int(((day.Begin.Minutes()+float64(tGiven.Hour()*60)+float64(tGiven.Minute()))/jt.Fminute*360.)/30./30.) % 12 + zodiacPositionEnd := int(((day.Begin.Minutes()+1440)/jt.Fminute*360.)/30./30.) % 12 if zodiacPositionBegin == zodiacPositionEnd { zods.Count = 1 zodBegin := zodiacPositionBegin * jt.Fminute / 360 * 30. * 30. zodEnd := (zodiacPositionEnd + 1) * jt.Fminute / 360 * 30. * 30. - tBegin := moon.BeginMoonDayToEarthDay(tGiven, time.Duration(zodBegin)*time.Minute, moonTable) - tEnd := moon.BeginMoonDayToEarthDay(tGiven, time.Duration(zodEnd)*time.Minute, moonTable) + var tBegin any = moon.BeginMoonDayToEarthDay(tGiven, time.Duration(zodBegin)*time.Minute, timeFormat, moonTable) + var tEnd any = moon.BeginMoonDayToEarthDay(tGiven, time.Duration(zodEnd)*time.Minute, timeFormat, moonTable) zods.Zodiac = make([]ZodiacDetailed, 1) - zods.Zodiac[0].Begin = tBegin - zods.Zodiac[0].End = tEnd + zods.Zodiac[0].Begin = &tBegin + zods.Zodiac[0].End = &tEnd zods.Zodiac[0].Name, zods.Zodiac[0].Emoji = getZodiacResp(zodiacPositionBegin) zods.Zodiac[0].NameLocalized = getZodiacRespLocalized(zodiacPositionBegin, lang) } else { @@ -40,25 +38,36 @@ func CurrentZodiacs(tGiven time.Time, loc *time.Location, lang string, moonTable zodBegin1 := (zodiacPositionBegin) * jt.Fminute / 360 * 30. * 30. zodEnd1 := (zodiacPositionBegin + 1) * jt.Fminute / 360 * 30. * 30. - tBegin1 := moon.BeginMoonDayToEarthDay(tGiven, time.Duration(zodBegin1)*time.Minute, moonTable) - tEnd1 := moon.BeginMoonDayToEarthDay(tGiven, time.Duration(zodEnd1)*time.Minute, moonTable) + var tBegin1 any = moon.BeginMoonDayToEarthDay(tGiven, time.Duration(zodBegin1)*time.Minute, timeFormat, moonTable) + var tEnd1 any = moon.BeginMoonDayToEarthDay(tGiven, time.Duration(zodEnd1)*time.Minute, timeFormat, moonTable) + zods.Zodiac = make([]ZodiacDetailed, 2) - zods.Zodiac[0].Begin = tBegin1 - zods.Zodiac[0].End = tEnd1 + zods.Zodiac[0].Begin = &tBegin1 + zods.Zodiac[0].End = &tEnd1 zods.Zodiac[0].Name, zods.Zodiac[0].Emoji = getZodiacResp(zodiacPositionBegin) zods.Zodiac[0].NameLocalized = getZodiacRespLocalized(zodiacPositionBegin, lang) - if int(endMoonDays.Minutes()/jt.Fminute) == 0 { - endMoonDays += (beginMoonDays + 24*time.Hour) - zodiacPositionEnd = int((endMoonDays.Minutes()/jt.Fminute*360.)/30./30.) % 12 + if int(day.End.Minutes()/jt.Fminute) == 0 { + day.End += (day.Begin + 24*time.Hour) + zodiacPositionEnd = int((day.End.Minutes()/jt.Fminute*360.)/30./30.) % 12 } zodBegin2 := (zodiacPositionEnd) * jt.Fminute / 360 * 30. * 30. zodEnd2 := (zodiacPositionEnd + 1) * jt.Fminute / 360 * 30. * 30. - tBegin2 := moon.BeginMoonDayToEarthDay(tGiven, time.Duration(zodBegin2)*time.Minute, moonTable) - tEnd2 := moon.BeginMoonDayToEarthDay(tGiven, time.Duration(zodEnd2)*time.Minute, moonTable) - zods.Zodiac[1].Begin = tBegin2 - zods.Zodiac[1].End = tEnd2 + + // to do: test + // when last sign comes to first sign + // zodBegin2 shild be == zodEnd1 + if zodBegin2 == 0 { + zodBegin2 = zodEnd1 + zodEnd2 += zodEnd1 + } + + var tBegin2 any = moon.BeginMoonDayToEarthDay(tGiven, time.Duration(zodBegin2)*time.Minute, timeFormat, moonTable) + var tEnd2 any = moon.BeginMoonDayToEarthDay(tGiven, time.Duration(zodEnd2)*time.Minute, timeFormat, moonTable) + + zods.Zodiac[1].Begin = &tBegin2 + zods.Zodiac[1].End = &tEnd2 zods.Zodiac[1].Name, zods.Zodiac[1].Emoji = getZodiacResp(zodiacPositionEnd) zods.Zodiac[1].NameLocalized = getZodiacRespLocalized(zodiacPositionEnd, lang) }