# Date/time utils

UTC timestamps, current dates and format conversions through a service's self.time attribute.

A service's `self.time` attribute accesses convenience wrappers around Python's [datetime](https://docs.python.org/3/library/datetime.html) and [Arrow's](https://github.com/arrow-py/arrow) objects.

## UTC now {#utc-now}

Call `self.time.utcnow()` to obtain current time in [UTC](https://en.wikipedia.org/wiki/UTC). Default format is `YYYY-MM-DD HH:mm:ss`. Returns string unless told not to serialize the result.

```python
# -*- coding: utf-8 -*-

# Zato
from zato.server.service import Service

class MyService(Service):

    def handle(self):

        # Default
        now = self.time.utcnow()
        self.logger.info('Now (1) is %s', now)

        # Custom output format, still in UTC
        now = self.time.utcnow('DD-MM-YY HH:mm')
        self.logger.info('Now (2) is %s', now)

        # Don't serialize to string
        now = self.time.utcnow(format=False)
        self.logger.info('Now (3) is %r', now)
```

Output in server logs:

```text
   INFO - Now (1) is 2025-01-26 13:34:24
   INFO - Now (2) is 26-01-15 13:34
   INFO - Now (3) is](Arrow [2025-01-26T13:34:24.738026+00:00]>
```

## Today {#today}

Returns current date. Default format is `YYYY-MM-DD` in UTC - both can be overridden. Converts output to string unless overridden.

```python
# -*- coding: utf-8 -*-

# Zato
from zato.server.service import Service

class MyService(Service):

    def handle(self):

        # Default
        today = self.time.today()
        self.logger.info('Today in UTC (1) is %s', today)

        # UTC, custom format
        today = self.time.today('DDMMYY')
        self.logger.info('Today in UTC (2) is %s', today)

        # Don't serialize to string
        today = self.time.today(format=False)
        self.logger.info('Today in UTC (3) is %r', today)

        # A user-provided timezone
        today = self.time.today(tz='Pacific/Fiji')
        self.logger.info('Today in Suva is %s', today)
```

Output in logs:

```text
INFO - Today in UTC (1) is 2025-01-26
INFO - Today in UTC (2) is 260115
INFO - Today in UTC (3) is](Arrow [2025-01-26T00:00:00+00:00]>
INFO - Today in Suva is 2025-01-27
```

## Reformatting {#reformatting}

Dates and time can be converted between formats using `self.time.reformat` - the method accepts a value, its format and a format it needs to be changed to. The value can be a string, [datetime](https://docs.python.org/3/library/datetime.html) or an [Arrow](https://github.com/arrow-py/arrow) object.

```python
# -*- coding: utf-8 -*-

# Zato
from zato.server.service import Service

class MyService(Service):

    def handle(self):

        # Convert from DD-MM-YYYY to YY.MM.DD

        value = '15-11-2029'
        self.logger.info('Was: %s', value)

        value = self.time.reformat(value, 'DD-MM-YYYY', 'YY.MM.DD')
        self.logger.info('Now: %s', value)
```

```text
INFO - Was: 15-11-2029
INFO - Now: 19.11.15
```

Anticipating the need to change source or target formats it's possible to store either or both in Redis so they are read in run-time without hardcoding anything in code.

Now instead of exact formats their names prefixed with 'kvdb:' are used. The prefix is stripped away and the names point to Redis keys that will contain the exact formats.

The pattern to use in Redis is `kvdb:date-format:$name` where $name is the name provided on input to self.time.reformat. For instance, a 'crm' format name should be stored in Redis under kvdb:date-format:crm key.

Supposing there are Redis keys as follows:

```text
127.0.0.1:6379> SET kvdb:date-format:crm "YY-MM-DD HH:mm"
OK
127.0.0.1:6379> SET kvdb:date-format:erp MM-DD-YY
OK
```

The following code will look up formats in Redis in order to reformat date from CRM to the format ERP expects. Should formats change, no updates to the code of the service will be needed.

```python
# -*- coding: utf-8 -*-

# Zato
from zato.server.service import Service

class MyService(Service):

    def handle(self):

        # Convert from DD-MM-YYYY to YY.MM.DD

        value = '15-11-2029 13:17'
        self.logger.info('Was: %s', value)

        value = self.time.reformat(value, 'kvdb:crm', 'kvdb:erp')
```

```text
INFO - Was: 15-11-2029 13:17
INFO - Now: 11-20-15
```

## Helper API programming tools and techniques {#helper-api-programming-tools-and-techniques}

- [Date and time utilities](https://zato.io/docs/dev/datetime.html)
- [Helper services](https://zato.io/docs/dev/helpers.html)
- [How to invoker other Zato services](https://zato.io/docs/dev/invoking-services.html)
- [Distributed locks](https://zato.io/docs/dev/dist-locks.html)
