graphql-scalars icon indicating copy to clipboard operation
graphql-scalars copied to clipboard

Add timezone scalar

Open Sytten opened this issue 4 years ago • 7 comments

Is your feature request related to a problem? Please describe.

Currently the libs has scalars to deal with datetime with timezone and time. But it would be nice to handle the timezone string itself like https://github.com/homoky/graphql-timezone.

Describe the solution you'd like Something similar to the library linked above, basically extract the moment timezone in a list and create a scalar.

Describe alternatives you've considered Home grown solution and String both work.

Sytten avatar Sep 20 '21 18:09 Sytten

Sounds cool! Would you create a PR for this?

ardatan avatar Sep 20 '21 19:09 ardatan

I can take a look into doing this since there's been no recent activity on this issue. Thoughts @ardatan?

tekkeon avatar Mar 19 '22 06:03 tekkeon

Sure @mkossoris :)

ardatan avatar Mar 19 '22 09:03 ardatan

If that is relevant, here is what we do:

import { GraphQLScalarType } from 'graphql';
import { GraphQLError } from 'graphql/error';
import { Kind } from 'graphql/language';
import { IANAZone } from 'luxon';

// Originaly from https://github.com/moment/luxon/blob/ad5d3f0a2fd8832189329ce7dd4030030ba9b53e/src/impl/util.js#L286
// Modified to force a style that is close to what Google accepts (uppercase each word)
const IANA_REGEX =
  /[A-Z][a-z_+-]{0,256}(:?\/[A-Z][a-z_+-]{0,256}(\/[A-Z][a-z_+-]{0,256})?)?/;

const sanitizeValue = (value: unknown) => {
  if (typeof value !== 'string') {
    throw new TypeError(`Value is not string: ${value}`);
  }

  if (!value.match(IANA_REGEX) || !IANAZone.isValidZone(value)) {
    throw new TypeError(`Value is not a valid IANA time zone: ${value}`);
  }

  return value;
};

export const GraphQLTimezone = new GraphQLScalarType({
  name: 'Timezone',
  description: 'The `TimeZone` scalar type represents an IANA time zone',
  parseValue: sanitizeValue,
  serialize: sanitizeValue,
  parseLiteral(ast) {
    if (ast.kind !== Kind.STRING) {
      throw new GraphQLError(
        `Can only sanitize Timezone strings, but got: ${ast.kind}`
      );
    }
    return sanitizeValue(ast.value);
  },
});

Sytten avatar Mar 19 '22 22:03 Sytten

@Sytten Awesome thanks for the some starter code! I was actually planning to use the built-in Intl API, and it looks like that's what both luxon and day.js use under the hood, so I will likely just do that to remove any need for dependencies.

tekkeon avatar Mar 19 '22 22:03 tekkeon

I went ahead and created a PR for this which should be in this thread. @Sytten if you wouldn't mind checking it out to ensure it does what you expect it should do, that would be great!

tekkeon avatar Mar 22 '22 20:03 tekkeon

@ardatan Looks like @Sytten has given the thumbs up just fyi :)

tekkeon avatar Mar 26 '22 20:03 tekkeon

looks like its done

Urigo avatar Mar 22 '23 16:03 Urigo