   end
 
   @doc """
+  Converts a number of gregorian seconds to a `DateTime` struct.
+
+  The returned `DateTime` will have `UTC` timezone, if you want other tiimezone, please use 
+  `DateTime.shift_zone/3`.
+
+  ## Examples
+
+      iex> DateTime.from_gregorian_seconds(1)
+      ~U[0000-01-01 00:00:01Z]
+      iex> DateTime.from_gregorian_seconds(63_755_511_991, {5000, 3})
+      ~U[2020-05-01 00:26:31.005Z]
+      iex> DateTime.from_gregorian_seconds(-1)
+      ~U[-0001-12-31 23:59:59Z]
+
+  """
+  @doc since: "1.11.0"
+  @spec from_gregorian_seconds(integer(), Calendar.microsecond(), Calendar.calendar()) :: t
+  def from_gregorian_seconds(
+        seconds,
+        {microsecond, precision} \\ {0, 0},
+        calendar \\ Calendar.ISO
+      )
+      when is_integer(seconds) do
+    {days, rest_seconds} = div_mod(seconds, @seconds_per_day)
+    microseconds_in_day = rest_seconds * @microseconds_per_second + microsecond
+    day_fraction = {microseconds_in_day, @microseconds_per_day}
+
+    {year, month, day, hour, minute, second, {microsecond, _}} =
+      calendar.naive_datetime_from_iso_days({days, day_fraction})
+
+    %DateTime{
+      calendar: calendar,
+      year: year,
+      month: month,
+      day: day,
+      hour: hour,
+      minute: minute,
+      second: second,
+      microsecond: {microsecond, precision},
+      std_offset: 0,
+      utc_offset: 0,
+      zone_abbr: "UTC",
+      time_zone: "Etc/UTC"
+    }
+  end
+
+  @doc """
+  Converts a `DateTime` struct to a number of gregorian seconds and microseconds.
+
+  ## Examples
+
+      iex> dt = %DateTime{year: 0000, month: 1, day: 1, zone_abbr: "UTC",
+      ...>                hour: 0, minute: 0, second: 1, microsecond: {0, 0},
+      ...>                utc_offset: 0, std_offset: 0, time_zone: "Etc/UTC"}
+      iex> DateTime.to_gregorian_seconds(dt)
+      {1, 0}
+
+      iex> dt = %DateTime{year: 2020, month: 5, day: 1, zone_abbr: "UTC",
+      ...>                hour: 0, minute: 26, second: 31, microsecond: {5000, 0},
+      ...>                utc_offset: 0, std_offset: 0, time_zone: "Etc/UTC"}
+      iex> DateTime.to_gregorian_seconds(dt)
+      {63_755_511_991, 5000}
+
+      iex> dt = %DateTime{year: 2020, month: 5, day: 1, zone_abbr: "CET",
+      ...>                hour: 1, minute: 26, second: 31, microsecond: {5000, 0},
+      ...>                utc_offset: 3600, std_offset: 0, time_zone: "Europe/Warsaw"}
+      iex> DateTime.to_gregorian_seconds(dt)
+      {63_755_511_991, 5000}
+
+  """
+  @doc since: "1.11.0"
+  @spec to_gregorian_seconds(Calendar.datetime()) :: {integer(), non_neg_integer()}
+  def to_gregorian_seconds(
+        %{
+          std_offset: std_offset,
+          utc_offset: utc_offset,
+          microsecond: {microsecond, _}
+        } = datetime
+      ) do
+    {days, day_fraction} =
+      datetime
+      |> to_iso_days()
+      |> apply_tz_offset(utc_offset + std_offset)
+
+    seconds_in_day = seconds_from_day_fraction(day_fraction)
+    {days * @seconds_per_day + seconds_in_day, microsecond}
+  end
+
+  @doc """
   Converts the given `datetime` to a string according to its calendar.
 
   ### Examples

        }

  @unix_days :calendar.date_to_gregorian_days({1970, 1, 1})

  @doc """
  Returns the current datetime in UTC.

    }
  end

  defp div_mod(int1, int2) do
    div = div(int1, int2)
    rem = int1 - div * int2

    if rem >= 0 do
      {div, rem}
    else
      {div - 1, rem + int2}
    end
  end

  defp seconds_from_day_fraction({parts_in_day, @seconds_per_day}),
    do: parts_in_day

  defp seconds_from_day_fraction({parts_in_day, parts_per_day}),
    do: div(parts_in_day * @seconds_per_day, parts_per_day)

  defimpl String.Chars do
    def to_string(datetime) do
      %{
