Enable Dark Mode!
how-to-use-date-and-datetime-fields-in-odoo-20.jpg
By: Vishnu P

How to Use Date and Datetime Fields in Odoo 20

Technical Odoo 20 Odoo Enterprises Odoo Community

Each Odoo model has a way to indicate when some event occurred or when it should be done, and Odoo provides two types of fields for that purpose – fields.Date and fields.Datetime. Both have static helper methods associated, and additionally Odoo's date_utils module provides more of those for ranges, fiscal periods, and relative calculations.

In this blog post, we'll consider the differences between the two fields and how to define and use their helpers in Odoo 20.

Declaring Date and Datetime fields

These two fields store different information and behave differently regarding time zones.

fields.Date stores only the day, for instance, 2026-10-17. It is stored in the database as a date field and provided to the Python code as an object of datetime.date. It has the YYYY-MM-DD format. It is time zone-less, which means all users will see the same day.

fields.Datetime stores both the day and the time together, for example, 2026-10-17 09:30:00. In the database, it is stored in a timestamp without a time zone field and provided to the Python code as a naive datetime.datetime object. Its format is YYYY-MM-DD HH:MM:SS. In Odoo, this field always stores its value as UTC and then converts it for each user into his/her timezone.

In case any of the two fields doesn't have a value, it will return False.

Here is the declaration of fields of each type:

class Booking(models.Model):
   _name = 'x.booking'
   _description = 'Booking'
   name = fields.Char(required=True)
   booking_date = fields.Date(
       string='Booking Date',
       default=fields.Date.context_today,
       index=True,
   )
   check_in = fields.Datetime(
       string='Check-in',
       default=fields.Datetime.now,
       required=True,
   )
   check_out = fields.Datetime(string='Check-out')

Default=fields.Datetime.now. This code is run by Odoo every time a new record is made, making each record have its own current time.

Working with Datetime: helper methods

Here are the five helper methods from the fields.Datetime methods that you will find useful.

1. fields.Datetime.now()

Returns the Current date and time in UTC without microseconds. Use this as the default for any datetime field.

from odoo import fields
print("Now:", fields.Datetime.now())

Output:

Now: 2026-10-17 09:03:48

2. fields.Datetime.today()

It returns the current date in UTC with the time reset to midnight. This can prove useful as the minimum value for a “since today” filter.

print("Today:", fields.Datetime.today())

Output:

Today: 2026-10-17 00:00:00

3. fields.Datetime.to_datetime(value)

Transforms a string to a datetime in Python, and a datetime is returned. An empty value results in False. Use it for values coming from context, controller, or external APIs.

from datetime import datetime
print(fields.Datetime.to_datetime('2026-10-17 15:30:00'))
print(fields.Datetime.to_datetime(datetime(2026, 10, 17, 15, 30)))

Output:

2026-10-17 15:30:00

2026-10-17 15:30:00

4. fields.Datetime.to_string(value)

This is the exact opposite of the previous approach: it converts a datetime to the string format of YYYY-MM-DD HH:MM:SS used by Odoo.

dt = datetime(2026, 10, 17, 15, 30)
print(fields.Datetime.to_string(dt))

Output:

2026-10-17 15:30:00

5. fields.Datetime.context_timestamp(record, timestamp)

Converts the saved UTC into an aware datetime object according to the user's time zone. This is the function that should be used before printing the time in a report or an email or a log, as those are executed by the server and do not benefit from browser conversion.

local_now = fields.Datetime.context_timestamp(self, fields.Datetime.now())
print("Local time:", local_now)

Output:

Local time: 2026-10-17 14:33:48+05:30

The value is 5 hours 30 minutes ahead of the UTC value from the previous example, which is precisely what will be displayed by the web client to the user in Asia/Kolkata.

Working with Date: helper methods

fields.Date has similar helpers, along with period and arithmetic operations that are similarly available in fields.Datetime.

6. fields.Date.today()

Returns the current date according to the server’s time (UTC). Does not take into account the user's time zone.

print("Today:", fields.Date.today())

Output:

Today: 2026-10-17

7. fields.Date.context_today(record)

Gives back today's date in the local time zone of the user. This is typically the date meant by "today" in most business rules. Both return different results only when the UTC date and the local date are different. This happens for users in Asia/Kolkata from 18:30 to 24:00 UTC.

print("Context today:", fields.Date.context_today(self))

Output, when it is 22:00 UTC on 17 October (03:30 on 18 October in Kerala):

Context today: 2026-10-18

Fields.date.today() returns 2026-10-17 at exactly the same time.

8. fields.Date.to_date(value)

Transforms a string, datetime, or date into a date object. An empty input will yield False.

print(fields.Date.to_date('2026-10-17'))
print(fields.Date.to_date(datetime(2026, 10, 17, 15, 30)))

Output:

2026-10-17

2026-10-17

9. fields.Date.to_string(value)

Formats a date to YYYY-MM-DD, the format required for storage and RPC.

from datetime import date
print(fields.Date.to_string(date(2026, 10, 17)))

Output:

2026-10-17

10. fields.Date.start_of(value, granularity)

Returns the first date in the period that includes the specified value. The periods can be years, quarters, months, weeks, or days, and weeks begin on Mondays. fields.Datetime.start_of functions are the same, except they also support hours.

d = date(2026, 10, 17)
print(fields.Date.start_of(d, 'year'))
print(fields.Date.start_of(d, 'quarter'))
print(fields.Date.start_of(d, 'month'))
print(fields.Date.start_of(d, 'week'))

Output:

2026-01-01

2026-10-01

2026-10-01

2026-10-12

11. fields.Date.end_of(value, granularity)

Returns the last day of the period. In case of Datetime, the output will be the last time instant of the period, such as 23:59:59.999999 for a day.

print(fields.Date.end_of(d, 'year'))
print(fields.Date.end_of(d, 'quarter'))
print(fields.Date.end_of(d, 'month'))
print(fields.Date.end_of(d, 'week'))

Output:

2026-12-31

2026-12-31

2026-10-31

2026-10-18

12. fields.Date.add(value, **kwargs)

Relative time addition. The keyword arguments are the same as in dateutil.relativedelta; therefore, month ends will be correctly adjusted: Adding a month to 31 January results in 28 February instead of throwing an exception.

print(fields.Date.add(date(2026, 10, 17), years=1))
print(fields.Date.add(date(2026, 1, 31), months=1))

Output:

2027-10-17

2026-02-28

13. fields.Date.subtract(value, **kwargs)

The opposite of add. It uses the same keyword arguments.

print(fields.Date.subtract(date(2026, 10, 17), days=7))
print(fields.Date.subtract(date(2026, 10, 17), months=1))

Output:

2026-10-10

2026-09-17

Going further with date_utils

The odoo.tools.date_utils module meets typical reporting requirements, such as providing days, getting the range for a month or a fiscal year, and adjusting dates in periods. Use this module once and reuse it:

from datetime import date, timedelta
from odoo.tools import date_utils

14. date_utils.date_range(start, end, step)

Produces the dates from the beginning through to the end (inclusive) using the provided step. This produces a generator, so use list() around it to view the dates.

days = date_utils.date_range(date(2026, 10, 1), date(2026, 10, 7), timedelta(days=2))
print(list(days))

Output:

[datetime.date(2026, 10, 1), datetime.date(2026, 10, 3),

 datetime.date(2026, 10, 5), datetime.date(2026, 10, 7)]

15. date_utils.get_month(value)

Returns the first and last day of the month in which the date falls. This is a fast way of generating the "this month" domain.

print(date_utils.get_month(date(2026, 10, 17)))

Output:

(datetime.date(2026, 10, 1), datetime.date(2026, 10, 31))

16. date_utils.get_quarter(value)

It will return the first and last day of the quarter in which the date falls.

print(date_utils.get_quarter(date(2026, 10, 17)))

Output:

(datetime.date(2026, 10, 1), datetime.date(2026, 12, 31))

17. date_utils.get_quarter_number(value)

Returns the quarter of the year, from 1 to 4.

print(date_utils.get_quarter_number(date(2026, 10, 17)))

Output:

4

18. date_utils.get_fiscal_year(value, day=31, month=12)

Returns the first and last days of the fiscal year that includes the date. The default ending for the fiscal year is December 31. Supply the day and month on which your business closes its fiscal year to override this. April-March years, found in India, have their fiscal year ending on March 31:

print(date_utils.get_fiscal_year(date(2026, 10, 17)))
print(date_utils.get_fiscal_year(date(2026, 10, 17), day=31, month=3))

Output:

(datetime.date(2026, 1, 1), datetime.date(2026, 12, 31))

(datetime.date(2026, 4, 1), datetime.date(2027, 3, 31))

19. date_utils.get_timedelta(quantity, granularity)

Constructs a relativedelta using a number and a time period (year, quarter, month, week, day, or hour). This can be helpful when the time period is based on the contents of a field such as a picklist with “week” and "month".

start = date(2026, 10, 17)
print(start + date_utils.get_timedelta(2, 'week'))
print(start + date_utils.get_timedelta(1, 'quarter'))

Output:

2026-10-31

2027-01-17

For just a date, use Date, and for both date and time, use Datetime. Odoo uses the UTC format for all Datetime data, but it displays the same in the time zone of the user. Helper functions and date_utils functions are very convenient when working with the current date, converting dates, and calculating date ranges. By using them, your Odoo 20 date and time-related code will be clear and accurate.

To read more about How to Configure and Use Date & Datetime Fields in Odoo 19, refer to our blog, How to Configure and Use Date & Datetime Fields in Odoo 19.


Frequently Asked Questions

What is the difference between Date and Datetime in Odoo?

Date stores only the day, like 2026-10-17. Datetime stores the day and the time, like 2026-10-17 09:30:00. Use Date for due dates and birthdays, and Datetime for exact moments like check-in time.

In which time zone does Odoo store a Datetime value?

Odoo always stores it in UTC. The web client shows it in each user’s own time zone. In Python code and reports, convert it first with fields.Datetime.context_timestamp(self, value).

Which method should I use to get today’s date?

Use fields.Date.context_today(self). It gives today’s date in the user’s time zone. fields.Date.today() uses the server’s UTC date, which can be one day behind or ahead for some users.

If you need any assistance in odoo, we are online, please chat with us.



0
Comments



Leave a comment



WhatsApp