Search code examples
javascriptreactjstypescriptnext.jsluxon

How to convert Luxon DateTime format into string or numbers?


I am using the following code to set up a Luxon clock for my project use.

import { DateTime } from 'luxon';
import React, { useEffect, useState } from 'react';

interface IProps {
  timezone: string;
  format: string;
  calendar?: string;
  daysOffset?: number;
}

const LiveDateTime: React.FC<IProps> = ({
  timezone,
  daysOffset,
  format,
  calendar,
}) => {
  const [timeLive, setTimeLive] = useState<DateTime>(DateTime.local());

  useEffect(() => {
    const interval = setInterval(() => {
      setTimeLive(
        DateTime.local()
          .setZone(timezone)
          .reconfigure({ outputCalendar: calendar })
          .plus({ days: daysOffset })
      );
    }, 1000);

    return () => clearInterval(interval);
  }, [timezone]);

  return <span>{timeLive?.toFormat(format)}</span>;
}; 
export default LiveDateTime;

Now, I am using this component in another place to define the month# of the current date.

const month = <LiveDateTime timezone={place?.timezone} format="M" />; // This returns '12' as a number in the UI (for December)
console.log(month)
getData(month); //this functions is supposed to return some data based on the given month.
//I get an error instead on this line that says, 'Argument of type 'Element' is not assignable to parameter of type 'number'.

When I print this in the console, I get an entire react.element object. I need to be able to use '12' as a number (for December) in getData()for the month variable. How can I covert this object into a number type or string type if necessary? P.S. I tried using pareInt(). doesn't work.


Solution

  • Rather than having this logic in a React component, you should move it to a custom React hook instead. This allows you to easily reuse its return value however you like.

    import { DateTime } from 'luxon';
    import React, { useEffect, useState } from 'react';
    
    const useLiveDataTime = ({
      timezone,
      daysOffset,
      format,
      calendar,
    }: IProps) => {
      const [timeLive, setTimeLive] = useState<DateTime>(DateTime.local());
    
      useEffect(() => {
        const interval = setInterval(() => {
          setTimeLive(
            DateTime.local()
              .setZone(timezone)
              .reconfigure({ outputCalendar: calendar })
              .plus({ days: daysOffset })
          );
        }, 1000);
    
        return () => clearInterval(interval);
      }, [timezone]);
    
      return timeLive?.toFormat(format);
    }; 
    
    export default useLiveDataTime;
    

    You can then retrieve the value as a string so you can pass it to other functions, or render it.

    import React from 'react';
    import useLiveDataTime from '<path-to>/use-live-date-time';
    
    const SomeComponent: React.FC = () => {
        const month = useLiveDataTime({ timezone: 'Europe/London', format: 'M' });
        console.log(month);
        getData(month);
    
        return <span>{month}</span>;
    };