IANA Time Zone Database Access for The Julia Programming Language

TimeZones.jl

IANA time zone database access for the Julia programming language. TimeZones.jl extends the Date/DateTime support for Julia to include a new time zone aware TimeType: ZonedDateTime.

Features

  • A new time zone aware TimeType: ZonedDateTime
  • Support for all time zones in the IANA time zone database (also known as the tz/zoneinfo/Olson database)
  • ZonedDateTime-Period arithmetic similar to that of DateTime
  • Local system time zone information as a TimeZone
  • Current system time in any TimeZone
  • Support for reading the tzfile format
  • String parsing of ZonedDateTime using DateFormat

Installation

TimeZones.jl can be installed through the Julia package manager:

julia> Pkg.add("TimeZones")

For detailed installation instructions see the documentation linked above.

Download Details:

Author: JuliaTime
Source Code: https://github.com/JuliaTime/TimeZones.jl 
License: View license

#julia #timezone 

IANA Time Zone Database Access for The Julia Programming Language
Desmond  Gerber

Desmond Gerber

1670062091

Change Timezone on Ubuntu 22.04

How to Change Timezone on Ubuntu 22.04. In this guide you are going to learn how to configure or setup your own timezone on Ubuntu server.

Having a local time is necessary on your server for some cronjob or any system related processes. By default, when a server is provisioned a default timezone will get configured automatically with the Coordinated Universal Time (UTC). You can change the timezone later using the below method.

Here you will learn how to use the timedatectl command to change timezone.

Prerequisites

Access to server using root or user who has sudo privileges.

Check Current Timezone

To check the configured time zone that your server uses currently you can use the following command on your Ubuntu 22.04 machine.

timedatectl

You will get an output similar to the one below.

Output
               Local time: Mon 2022-05-23 01:50:57 UTC
           Universal time: Mon 2022-05-23 01:50:57 UTC
                 RTC time: Mon 2022-05-23 01:50:57
                Time zone: Etc/UTC (UTC, +0000)
System clock synchronized: yes
              NTP service: active
          RTC in local TZ: no

Now the time zone configured is UTC.

The system timezone is configured by creating a symbolic link of /etc/localtime to a binary timezone identifier in the /usr/share/zoneinfo directory.

You can also view the timezone by viewing the timezone file created inside the etc directory.

cat /etc/timezone
Output
Etc/UTC

Change Timezone in Ubuntu

Now you can proceed to change the default timezone to your location. The time zones in Ubuntu uses the “Region/City” format.

So, you need to find your region and city using the list-timezones option with the timedatectl command.

timedatectl list-timezones

This command outputs all the available time zones.

Output
Africa/Abidjan
Africa/Accra
Africa/Algiers
Africa/Bissau
Africa/Cairo
. . .

Press Enter to load additional available time zones.

Once you have found your time zone you use the below format to setup your own time zone.

sudo timedatectl set-timezone your_time_zone

If your time zone is America/Los_Angeles, your format should be like this

sudo timedatectl set-timezone America/Chicago

Now you can again use the timedatectl command to confirm the time zone update.

Output
               Local time: Sun 2022-05-22 20:53:00 CDT
           Universal time: Mon 2022-05-23 01:53:00 UTC
                 RTC time: Mon 2022-05-23 01:53:00
                Time zone: America/Chicago (CDT, -0500)
System clock synchronized: yes
              NTP service: active
          RTC in local TZ: no

That’s all.

Conclusion

Now you have learned how to change time zone in your Ubuntu 22.04 machine.

Thanks for your time. If you face any problem or any feedback, please leave a comment below.

Original article source at: https://www.cloudbooklet.com/

#ubuntu #timezone 

Change Timezone on Ubuntu 22.04

UTime.jl: Universal Time using Local System Timezone

UTime.jl

Universal Time using local system timezone

Experimental: passes initial tests

This module lets you have whatever it is that your local system believes is Universal Time relative to the local time zone, present, past and future. And it lets you use the things that come with Base.Dates (for the most part .. not exaustively).

If you find errors, omissions, better ways, please raise an issue here.

Asks:

Do Not store UT typed values in a jld file -- store their strings, they will be rereadable.

This is transitional -- working in multiple timezones is different.

The module requires the local system provides a Standard C compliant maketm_r().

Try UTime.ok() (not exported), if it is false is module should not be used.

This is transitional -- working in multiple timezones is different.

Offers:

functionaction
ut()get the current date&time as it is in UT
ut(dtm::DateTime)convert the local date&time dtm to UT
localtime()get the current date&time as it is in local time
localtime(utm::UT)convert the UT date&time to local time
UT(...)like DateTime(...)
year(utm::UT)..like year,month...
Year(utm::UT)..like Year,Month...
format(utm,DateFormat)like format(dt::DateTime, DateFormat)
much other stuffused as with DateTime

importall UTime

exports
gmt, ut, localtime, UT # gmt is an alias for ut

exports (imported from Base.Dates)
Year, Month, Week, Day, Hour, Minute, Second, Millisecond,
year, month, week, day, hour, minute, second, millisecond, 
dayofyear, dayofmonth, dayofweek, yearmonthday, yearmonth, monthday, 
dayofweekofmonth, daysofweekinmonth, quarterofyear, dayofquarter,
firstdayofyear, lastdayofyear, firstdayofquarter, lastdayofquarter,
firstdayofmonth, lastdayofmonth, firstdayofweek, lastdayofweek, 
daysinmonth, daysinyear, monthname, monthabbr, dayname, dayabbr,
isleapyear, format, ISOUniversalTimeFormat, 
adjust, tonext, toprev, tofirst, tolast, recur,
(+), (-), (.+), (.-)

Download Details:

Author: J-Sarnoff
Source Code: https://github.com/J-Sarnoff/UTime.jl 
License: MIT license

#julia #local #system #timezone 

UTime.jl: Universal Time using Local System Timezone
Rupert  Beatty

Rupert Beatty

1665921600

Toolkit To Parse, Validate, Manipulate, Compare & Display Dates

SwiftDate

Toolkit to parse, validate, manipulate, compare and display dates, time & timezones in Swift.

What's This?

SwiftDate is the definitive toolchain to manipulate and display dates and time zones on all Apple platform and even on Linux and Swift Server Side frameworks like Vapor or Kitura.
Over 3 million of downloads on CocoaPods.

From simple date manipulation to complex business logic SwiftDate maybe the right choice for your next project.

  •  Easy Date Parsing (custom formats, iso8601, rss & many more)
  •  Easy Date Formatting even with colloquial formatter and 140+ supported languages
  •  Easy math operations with time units (2.hours + 5.minutes...)
  •  Intuitive components extraction (day, hour, nearestHour, weekdayNameShort etc.)
  •  Derivated dates generation (nextWeek, nextMonth, nextWeekday, tomorrow...)
  •  Over 20+ fine grained date comparison functions (isToday, isTomorrow, isSameWeek, isNextYear...)
  •  Swift 4's Codable Support
  •  Random dates generation
  •  Fine grained date enumeration functions
  •  Time period support
  •  Convert TimeIntervals to other units (2.hours.toUnits(.minutes))

and of course...

  • IT'S TESTED!. As 5.x the project has 90% of code coverage (want help us? write some unit tests and make a PR)
  • IT'S FULLY DOCUMENTED!, both with a complete guide and with Jazzy!
  • WE LOVE PLAYGROUND! Check out our interactive playground!

Start with SwiftDate

The entire library is fully documented both via XCode method inspector and a complete markdown documentation you can found below.

Explore SwiftDate

From simple date manipulation to complex business logic SwiftDate maybe the right choice for your next project.

Let me show to you the main features of the library:

1. Date Parsing

SwiftDate can recognize all the major datetime formats automatically (ISO8601, RSS, Alt RSS, .NET, SQL, HTTP...) and you can also provide your own formats. Creating a new date has never been so easy!

// All default datetime formats (15+) are recognized automatically
let _ = "2010-05-20 15:30:00".toDate()
// You can also provide your own format!
let _ = "2010-05-20 15:30".toDate("yyyy-MM-dd HH:mm")
// All ISO8601 variants are supported too with timezone parsing!
let _ = "2017-09-17T11:59:29+02:00".toISODate()
// RSS, Extended, HTTP, SQL, .NET and all the major variants are supported!
let _ = "19 Nov 2015 22:20:40 +0100".toRSS(alt: true)

2. Date Manipulation

Date can be manipulated by adding or removing time components using a natural language; time unit extraction is also easy and includes the support for timezone, calendar and locales!

Manipulation can be done with standard math operators and between dates, time intervals, date components and relevant time units!

// Math operations support time units
let _ = ("2010-05-20 15:30:00".toDate() + 3.months - 2.days)
let _ = Date() + 3.hours
let _ = date1 + [.year:1, .month:2, .hour:5]
let _ = date1 + date2
// extract single time unit components from date manipulation
let over1Year = (date3 - date2).year > 1

3. Date Comparison

SwiftDate include an extensive set of comparison functions; you can compare two dates by granularity, check if a date is an particular day, range and practically any other comparison you ever need.

Comparison is also available via standard math operators like (>, >=, <, <=).

// Standard math comparison is allowed
let _ = dateA >= dateB || dateC < dateB

// Complex comparisons includes granularity support
let _ = dateA.compare(toDate: dateB, granularity: .hour) == .orderedSame
let _ = dateA.isAfterDate(dateB, orEqual: true, granularity: .month) // > until month granularity
let _ = dateC.isInRange(date: dateA, and: dateB, orEqual: true, granularity: .day) // > until day granularity
let _ = dateA.earlierDate(dateB) // earlier date
let _ = dateA.laterDate(dateB) // later date

// Check if date is close to another with a given precision
let _ = dateA.compareCloseTo(dateB, precision: 1.hours.timeInterval

// Compare for relevant events:
// .isToday, .isYesterday, .isTomorrow, .isWeekend, isNextWeek
// .isSameDay, .isMorning, .isWeekday ...
let _ = date.compare(.isToday)
let _ = date.compare(.isNight)
let _ = date.compare(.isNextWeek)
let _ = date.compare(.isThisMonth)
let _ = date.compare(.startOfWeek)
let _ = date.compare(.isNextYear)
// ...and MORE THAN 30 OTHER COMPARISONS BUILT IN

// Operation in arrays (oldestIn, newestIn, sortedByNewest, sortedByOldest...)
let _ = DateInRegion.oldestIn(list: datesArray)
let _ = DateInRegion.sortedByNewest(list: datesArray)

4. Date Creation with Region (Timezone, Calendar & Locale)

You can create new dates from a string, time intervals or using date components. SwiftDate offers a wide set of functions to create and derivate your dates even with random generation!

// All dates includes timezone, calendar and locales!
// Create from string
let rome = Region(calendar: Calendars.gregorian, zone: Zones.europeRome, locale: Locales.italian)
let date1 = DateInRegion("2010-01-01 00:00:00", region: rome)!

// Create date from intervals
let _ = DateInRegion(seconds: 39940, region: rome)
let _ = DateInRegion(milliseconds: 5000, region: rome)

// Date from components
let _ = DateInRegion(components: {
    $0.year = 2001
    $0.month = 9
    $0.day = 11
    $0.hour = 12
    $0.minute = 0
}, region: rome)
let _ = DateInRegion(year: 2001, month: 1, day: 5, hour: 23, minute: 30, second: 0, region: rome)

// Random date generation with/without bounds
let _ = DateInRegion.randomDate(region: rome)
let _ = DateInRegion.randomDate(withinDaysBeforeToday: 5)
let _ = DateInRegion.randomDates(count: 50, between: lowerLimitDate, and: upperLimitDate, region: rome)

5. Derivated Dates

Date can be also generated starting from other dates; SwiftDate includes an extensive set of functions to generate. Over 20 different derivated dates can be created easily using dateAt() function.

let _ = DateInRegion().dateAt(.endOfDay) // today at the end of the day
// Over 20 different relevant dates including .startOfDay,
// .endOfDay, .startOfWeek, .tomorrow, .nextWeekday, .nextMonth, .prevYear, .nearestMinute and many others!
let _ = dateA.nextWeekday(.friday) // the next friday after dateA
let _ = (date.dateAt(.startOfMonth) - 3.days)
let _ = dateA.compare(.endOfWeek)

// Enumerate dates in range by providing your own custom
// increment expressed in date components
let from = DateInRegion("2015-01-01 10:00:00", region: rome)!
let to = DateInRegion("2015-01-02 03:00:00", region: rome)!
let increment2 = DateComponents.create {
    $0.hour = 1
    $0.minute = 30
    $0.second = 10
}
// generate dates in range by incrementing +1h,30m,10s each new date
let dates = DateInRegion.enumerateDates(from: fromDate2, to: toDate2, increment: increment2)

// Get all mondays in Jan 2019
let mondaysInJan2019 = Date.datesForWeekday(.monday, inMonth: 1, ofYear: 2019)

// Altering time components
let _ = dateA.dateBySet(hour: 10, min: 0, secs: 0)

// Truncating a date
let _ = dateA.dateTruncated(at: [.year,.month,.day]) // reset all time components keeping only date

// Rounding a date
let _ = dateA.dateRoundedAt(.toMins(10))
let _ = dateA.dateRoundedAt(.toFloor30Mins)

// Adding components
let _ = dateA.dateByAdding(5,.year)

// Date at the start/end of any time component
let _ = dateA.dateAtEndOf(.year) // 31 of Dec at 23:59:59
let _ = dateA.dateAtStartOf(.day) // at 00:00:00 of the same day
let _ = dateA.dateAtStartOf(.month) // at 00:00:00 of the first day of the month

6. Components Extraction

You can extract components directly from dates and it includes the right value expressed in date's region (the right timezone and set locale!).

// Create a date in a region, London but with the lcoale set to IT
let london = Region(calendar: .gregorian, zone: .europeLondon, locale: .italian)
let date = DateInRegion("2018-02-05 23:14:45", format: dateFormat, region: london)!

// You can extract any of the all available time units.
// VALUES ARE EXPRESSED IN THE REGION OF THE DATE (THE RIGHT TIMEZONE).
// (you can still get the UTC/absolute value by getting the inner's absoluteDate).

let _ = date.year // 2018
let _ = date.month // 2
let _ = date.monthNameDefault // 'Febbraio' as the locale is the to IT!
let _ = date.firstDayOfWeek // 5
let _ = date.weekdayNameShort // 'Lun' as locale is the to IT
// ... all components are supported: .year, .month, .day, .hour, .minute, .second,
// .monthName, .weekday, .nearestHour, .firstDayOfWeek. .quarter and so on...

7. Switch between timezones/locale and calendars

You can easily convert any date to another region (aka another calendar, locale or timezone) easily! New date contains all values expressed into the destination reason

// Conversion between timezones is easy using convertTo(region:) function
let rNY = Region(calendar: Calendars.gregorian, zone: Zones.americaNewYork, locale: Locales.english)
let rRome = Region(calendar: Calendars.gregorian, zone: Zones.europeRome, locale: Locales.italian)
let dateInNY = "2017-01-01 00:00:00".toDate(region: rNY)
let dateInRome = dateInNY?.convertTo(region: rRome)!
print(dateInRome.toString()) // "dom gen 01 06:00:00 +0100 2017\n"

// You can also convert single region's attributes
let dateInIndia = dateInNY?.convertTo(timezone: Zones.indianChristmas, locale: Locales.nepaliIndia)
print("\(dateInIndia!.toString())") // "आइत जनवरी ०१ १२:००:०० +0700 २०१७\n"

8. Date Formatting

Date formatting is easy, you can specify your own format, locale or use any of the provided ones.

// Date Formatting
let london = Region(calendar: .gregorian, zone: .europeLondon, locale: .english)
let date = ... // 2017-07-22T18:27:02+02:00 in london region
let _ = date.toDotNET() // /Date(1500740822000+0200)/
let _ = date.toISODate() // 2017-07-22T18:27:02+02:00
let _ = date.toFormat("dd MMM yyyy 'at' HH:mm") // "22 July 2017 at 18:27"

// You can also easily change locale when formatting a region
let _ = date.toFormat("dd MMM", locale: .italian) // "22 Luglio"

// Time Interval Formatting as Countdown
let interval: TimeInterval = (2.hours.timeInterval) + (34.minutes.timeInterval) + (5.seconds.timeInterval)
let _ = interval.toClock() // "2:34:05"

// Time Interval Formatting by Components
let _ = interval.toString {
    $0.maximumUnitCount = 4
    $0.allowedUnits = [.day, .hour, .minute]
    $0.collapsesLargestUnit = true
    $0.unitsStyle = .abbreviated
} // "2h 34m"

9. Relative Date Formatting (fully customizable!)

Relative formatting is all new in SwiftDate; it supports 120+ languages with two different styles (.default, .twitter), 9 flavours (.long, .longTime, .longConvenient, .short, .shortTime, .shortConvenient, .narrow, .tiny, .quantify) and all of them are customizable as you need. The extensible format allows you to provide your own translations and rules to override the default behaviour.

// Twitter Style
let _ = (Date() - 3.minutes).toRelative(style: RelativeFormatter.twitterStyle(), locale: Locales.english) // "3m"
let _ = (Date() - 6.minutes).toRelative(style: RelativeFormatter.twitterStyle(), locale: Locales.italian) // "6 min fa"

// Default Style
let _ = (now2 - 5.hours).toRelative(style: RelativeFormatter.defaultStyle(), locale: Locales.english) // "5 hours ago"
let y = (now2 - 40.minutes).toRelative(style: RelativeFormatter.defaultStyle(), locale: Locales.italian) // "45 minuti fa"

10. Codable Support

Both DateInRegion and Region fully support the new Swift's Codable protocol. This mean you can safely encode/decode them:

// Encoding/Decoding a Region
let region = Region(calendar: Calendars.gregorian, zone: Zones.europeOslo, locale: Locales.english)
let encodedJSON = try JSONEncoder().encode(region)
let decodedRegion = try JSONDecoder().decode(Region.self, from: encodedJSON)

// Encoding/Decoding a DateInRegion
let date = DateInRegion("2015-09-24T13:20:55", region: region)
let encodedDate = try JSONEncoder().encode(date)
let decodedDate = try JSONDecoder().decode(DateInRegion.self, from: encodedDate)

11. Time Periods

SwiftDate integrates the great Matthew York's DateTools module in order to support Time Periods.

See Time Periods section of the documentation.

Download Details:

Author: Malcommac
Source Code: https://github.com/malcommac/SwiftDate 
License: MIT license

#swift #date #timezone 

Toolkit To Parse, Validate, Manipulate, Compare & Display Dates

Surgically Polyfills Timezone Support in Intl.DateTimeformat API

Intl.DateTimeFormat timezone polyfill

Surgically polyfills timezone support in Intl.DateTimeFormat API 

Some browsers do not support arbitrary time zone in Intl.DateTimeFormat API (becuase its optional as per ECMA-402 standard). This polyfill is only to bring this support. Polyfill contains historical timezone data, CLDR data & tiny code to polyfill this support.

How to use?

Install via nodejs:

npm i date-time-format-timezone

And then import in your code:

require('date-time-format-timezone'); // polyfill is ready

In the browser

include everything:

<script src="https://unpkg.com/date-time-format-timezone@latest/build/browserified/date-time-format-timezone-complete-min.js">

or include individual files:

<script src="https://unpkg.com/date-time-format-timezone@latest/build/browserified/date-time-format-timezone-no-data-min.js">
<script src="https://unpkg.com/date-time-format-timezone@latest/build/browserified/data/locales/locale-en-US-POSIX.js">
<script src="https://unpkg.com/date-time-format-timezone@latest/build/browserified/data/metazone.js">
<script src="https://unpkg.com/date-time-format-timezone@latest/build/browserified/data/timezones/tzdata-america-los_angeles.js">

This polyfill can add this support.

new Intl.DateTimeFormat('hi', {
    timeZone: 'Asia/Calcutta',
    timeZoneName:'long',
    year: 'numeric',
    month: 'numeric',
    day: 'numeric',
    hour: 'numeric',
    minute: 'numeric',
}).format(new Date());

"११/१/२०१७, पू १:२६ भारतीय मानक समय"


new Intl.DateTimeFormat('en', {
    timeZone: 'America/Los_Angeles',
    timeZoneName:'long',
    year: 'numeric',
    month: 'numeric',
    day: 'numeric',
    hour: 'numeric',
    minute: 'numeric',
}).format(new Date());

"1/10/2017, 12:00 PM Pacific Standard Time"

Support

APISupport
Intl.DateTimeFormat
Date.toLocaleString
Date.toLocaleTimeString
Date.toLocaleTimeString

Generate latest data from www.iana.org.

git checkout https://github.com/yahoo/date-time-format-timezone.git
npm install
grunt download
grunt
npm publish

Browserified file size

 Minifiedgzipped
complete2.64MB322KB
top zones1 only no locale369.32KB71KB
all zones no locale303.19KB75KB
top zones1 top locale2641.86KB148KB

*1. top zones are custom listed timezones here.

*2. top locales are custom listed locales here.

References

  1. http://www.unicode.org/reports/tr35/tr35-dates.html#Using_Time_Zone_Names
  2. http://icu-project.org/apiref/icu4j/com/ibm/icu/text/TimeZoneNames.html

Download Details:

Author: Formatjs
Source Code: https://github.com/formatjs/date-time-format-timezone 
License: View license

#javascript #date #time #timezone 

Surgically Polyfills Timezone Support in Intl.DateTimeformat API
Dexter  Goodwin

Dexter Goodwin

1663051680

10 Popular JavaScript Date Libraries

In today's post we will learn about 10 Popular JavaScript Date Libraries.

Wrangling dates and times in JavaScript can be a headache. JavaScript date libraries provide user-friendly APIs and useful utilities that alleviate some of that pain. But with so many options how do you pick the best one? In this post we delve into the world of JavaScript date libraries to help you choose. 

Table of contents:

  • Moment - Parse, validate, manipulate, and display dates in JavaScript.
  • Moment-timezone - Timezone support for moment.js.
  • jquery-timeago - A jQuery plugin that makes it easy to support automatically updating fuzzy timestamps (e.g. "4 minutes ago").
  • Timezone-js - Timezone-enabled JavaScript Date object. Uses Olson zoneinfo files for timezone data.
  • Date - Date() for humans.
  • ms.js - Tiny millisecond conversion utility.
  • Countdown.js - Super simple countdowns.
  • Timeago.js - Simple library (less then 2kb) used to format date with *** time ago statement.
  • Fecha - Lightweight date formatting and parsing (~2KB). Meant to replace parsing and formatting functionality of moment.js.
  • Date-fns - Modern JavaScript date utility library.

1 - Moment: Parse, validate, manipulate, and display dates in JavaScript.

A JavaScript date library for parsing, validating, manipulating, and formatting dates.

Using Moment

Moment was designed to work both in the browser and in Node.js.

All code should work in both of these environments, and all unit tests are run in both of these environments.

Currently, the following browsers are used for the ci system: Chrome on Windows XP, IE 8, 9, and 10 on Windows 7, IE 11 on Windows 10, latest Firefox on Linux, and latest Safari on OSX 10.8 and 10.11.

If you want to try the sample codes below, just open your browser's console and enter them.

Node.js

npm install moment
var moment = require('moment'); // require
moment().format(); 

Or in ES6 syntax:

import moment from 'moment';
moment().format();

Note: if you want to work with a particular variation of moment timezone, for example using only data from 2012-2022, you will need to import it from the builds directory like so:

import moment from 'moment-timezone/builds/moment-timezone-with-data-2012-2022';

Note: In 2.4.0, the globally exported moment object was deprecated. It will be removed in next major release.

Browser

<script src="moment.js"></script>
<script>
    moment().format();
</script>

Moment.js is available on cdnjs.com and on jsDelivr.

View on Github

2 - Moment-timezone: Timezone support for moment.js.

IANA Time zone support for Moment.js

Project Status

Moment-Timezone is an add-on for Moment.js. Both are considered legacy projects, now in maintenance mode. In most cases, you should choose a different library.

For more details and recommendations, please see Project Status in the Moment docs.

Examples

var june = moment("2014-06-01T12:00:00Z");
june.tz('America/Los_Angeles').format('ha z'); // 5am PDT
june.tz('America/New_York').format('ha z');    // 8am EDT
june.tz('Asia/Tokyo').format('ha z');          // 9pm JST
june.tz('Australia/Sydney').format('ha z');    // 10pm EST

var dec = moment("2014-12-01T12:00:00Z");
dec.tz('America/Los_Angeles').format('ha z');  // 4am PST
dec.tz('America/New_York').format('ha z');     // 7am EST
dec.tz('Asia/Tokyo').format('ha z');           // 9pm JST
dec.tz('Australia/Sydney').format('ha z');     // 11pm EST

View on Github

3 - JQuery-timeago: A jQuery plugin that makes it easy to support automatically updating fuzzy timestamps (e.g. "4 minutes ago").

Timeago is a jQuery plugin that makes it easy to support automatically updating fuzzy timestamps (e.g. "4 minutes ago" or "about 1 day ago") from ISO 8601 formatted dates and times embedded in your HTML (à la microformats).

Usage

First, load jQuery and the plugin:

<script src="jquery.min.js" type="text/javascript"></script>
<script src="jquery.timeago.js" type="text/javascript"></script>

Now, let's attach it to your timestamps on DOM ready - put this in the head section:

<script type="text/javascript">
   jQuery(document).ready(function() {
     $("time.timeago").timeago();
   });
</script>

This will turn all <time> elements with a class of timeago and a datetime attribute formatted according to the ISO 8601 standard:

<time class="timeago" datetime="2011-12-17T09:24:17Z">December 17, 2011</time>

into something like this:

<time class="timeago" datetime="2011-12-17T09:24:17Z" title="December 17, 2011">about 1 day ago</time>

<abbr> elements (or any other HTML elements) are also supported (this is for legacy microformat support and was originally supported by the library before the time element was introduced to HTML5):

<abbr class="timeago" title="2011-12-17T09:24:17Z">December 17, 2011</abbr>

As time passes, the timestamps will automatically update.

If you want to update a timestamp programatically later, call the update function with a new ISO8601 timestamp of Date object. For example:

$("time#some_id").timeago("update", "2013-12-17T09:24:17Z");
// or
$("time#some_id").timeago("update", new Date());

For more usage and examples: http://timeago.yarp.com/

For different language configurations: visit the locales directory.

View on Github

4 - Timezone-js: Timezone-enabled JavaScript Date object. Uses Olson zoneinfo files for timezone data.

A timezone-enabled, drop-in replacement for the stock JavaScript Date. The timezoneJS.Date object is API-compatible with JS Date, with the same getter and setter methods -- it should work fine in any code that works with normal JavaScript Dates.

Overview

The timezoneJS.Date object gives you full-blown timezone support, independent from the timezone set on the end-user's machine running the browser. It uses the Olson zoneinfo files for its timezone data.

The constructor function and setter methods use proxy JavaScript Date objects behind the scenes, so you can use strings like '10/22/2006' with the constructor. You also get the same sensible wraparound behavior with numeric parameters (like setting a value of 14 for the month wraps around to the next March).

The other significant difference from the built-in JavaScript Date is that timezoneJS.Date also has named properties that store the values of year, month, date, etc., so it can be directly serialized to JSON and used for data transfer.

Setup

This section shows the most common way of setting up timezone-js. In the 'Customizing' section below you can find alternative approaches.

First you'll need to include the code on your page. Both timezoneJS.Date, and the supporting code it needs in timezoneJS.timezone are bundled in the date.js file in src directory. Include the code on your page with a normal JavaScript script include, like so:

<script type="text/javascript" src="/js/timezone-js/src/date.js">

Next you'll need the Olson time zone files -- timezoneJS.Date uses the raw Olson data to calculate timezone offsets. The Olson region files are simple, structured text data, which download quickly and parse easily. (They also compress to a very small size.)

Here is an example of how to get the Olson time zone files:

##!/bin/bash

# NOTE: Run from your webroot

# Create the /tz directory
mkdir tz

# Download the latest Olson files
curl ftp://ftp.iana.org/tz/tzdata-latest.tar.gz -o tz/tzdata-latest.tar.gz

# Expand the files
tar -xvzf tz/tzdata-latest.tar.gz -C tz

# Optionally, you can remove the downloaded archives.
rm tz/tzdata-latest.tar.gz

Then you'll need to make the files available to the timezoneJS.timezone code, and initialize the code to parse your default region. (This will be North America if you don't change it). No sense in downloading and parsing timezone data for the entire world if you're not going to be using it.

Put your directory of Olson files somewhere under your Web server root, and point timezoneJS.timezone.zoneFileBasePath to it. Then call the init function. Your code will look something like this:

timezoneJS.timezone.zoneFileBasePath = '/tz';
timezoneJS.timezone.init({ callback: cb });

If you use timezoneJS.Date with Fleegix.js, jQuery or jQuery-compatible libraries (like Zepto.js), there's nothing else you need to do -- timezones for North America will be loaded and parsed on initial page load, and others will be downloaded and parsed on-the-fly, as needed. If you want to use this code with some other JavaScript toolkit, you'll need to overwrite your own transport method by setting timezoneJS.timezone.transport = someFunction method. Take a look at test-utils.js in spec for an example.

NOTE: By default init() is async so you'll need to specify a callback function such as init({ callback: cb }). Otherwise set init({ async: false }) to turn off async.

View on Github

5 - Date: Date() for humans.

Date is an english language date parser for node.js and the browser. 

Installation

On the server or in the browser:

npm install date.js

Standalone:

Standalone is also AMD-compatible

Examples

date('10 minutes from now')
date('in 5 hours')
date('at 5pm')
date('at 12:30')
date('at 23:35')
date('in 2 days')
date('tuesday at 9am')
date('monday at 1:00am')
date('last monday at 1:00am')
date('tomorrow at 3pm')
date('yesterday at 12:30am')
date('5pm tonight')
date('tomorrow at noon')
date('next week tuesday')
date('next week tuesday at 4:30pm')
date('2 weeks from wednesday')
date('tomorrow night at 9')
date('tomorrow afternoon')
date('this morning at 9')
date('at 12:30pm')
date('tomorrow at 9 in the morning')
date('2 years from yesterday at 5pm')
date('last month')
date('2nd of January')
date('1st of March')
date('1 st of March')
date('31st of September 4:00am')
date('1st of January 4:00am')
date('9th of December 4:00am')
date('tomorrow afternoon at 4:30pm 1 month from now')
date('10 seconds ago')
date('1 minute ago')
date('2 hours ago')
date('5 weeks ago')
date('2 months ago')
date('1 year ago')
date('an hour later')
date('2w from wednesday')
date('2nd day of January')
date('two hours later')
date('a fortnight from wednesday')
date('a minute ago')

date('at 12:30')
date('at 12.30')
date('tuesday at 9')
date('tomorrow at 15')

View on Github

6 - MS.js: Tiny millisecond conversion utility.

Use this package to easily convert various time formats to milliseconds.

Examples

ms('2 days')  // 172800000
ms('1d')      // 86400000
ms('10h')     // 36000000
ms('2.5 hrs') // 9000000
ms('2h')      // 7200000
ms('1m')      // 60000
ms('5s')      // 5000
ms('1y')      // 31557600000
ms('100')     // 100
ms('-3 days') // -259200000
ms('-1h')     // -3600000
ms('-200')    // -200

Convert from Milliseconds

ms(60000)             // "1m"
ms(2 * 60000)         // "2m"
ms(-3 * 60000)        // "-3m"
ms(ms('10 hours'))    // "10h"

Time Format Written-Out

ms(60000, { long: true })             // "1 minute"
ms(2 * 60000, { long: true })         // "2 minutes"
ms(-3 * 60000, { long: true })        // "-3 minutes"
ms(ms('10 hours'), { long: true })    // "10 hours"

View on Github

7 - Countdown.js: Super simple countdowns.

Countdown.js is a library that allows developers to set countdowns for any kind of interaction. For example, if you would like to submit a form, Countdown.js allows you to set a 5 second countdown and give the user a chance to cancel the submission. 

Installation

If you use bower:

bower install countdown.js

Otherwise, you can download it from here.

API

new Countdown(duration, onTick, onComplete)

Begins a countdown. After duration time has passed, the function onComplete will be executed. Every second, the onTick function will be executed.

Example:

var countdown = new Countdown(5, function(seconds) {
  console.log(seconds); //log the number of seconds that have passed
}, function() {
   console.log("Countdown complete!") //log that the countdown has complete
});

abort()

Terminates countdown.

Example:

countdown.abort();

getRemainingTime()

Returns remaining time in seconds.

Example:

countdown.getRemainingTime(); //=> 4

View on Github

8 - Timeago.js: Simple library (less then 2kb) used to format date with *** time ago statement.

timeago.js is a nano library(less than 2 kb) used to format datetime with *** time ago statement. eg: '3 hours ago'.

  • i18n supported.
  • Time ago and time in supported.
  • Real-time render supported.
  • Node and browser supported.
  • Well tested.

Such as

just now
12 seconds ago
2 hours ago
3 days ago
3 weeks ago
2 years ago

in 12 seconds
in 3 minutes
in 24 days
in 6 months

Usage

  • install
npm install timeago.js
  • import
import { format, render, cancel, register } from 'timeago.js';

or import with script tag in html file and access global variable timeago.

<script src="dist/timeago.min.js"></script>
  • example
// format the time with locale
format('2016-06-12', 'en_US');

View on Github

9 - Fecha: Lightweight date formatting and parsing (~2KB). Meant to replace parsing and formatting functionality of moment.js.

Lightweight date formatting and parsing (~2KB). Meant to replace parsing and formatting functionality of moment.js.

NPM

npm install fecha --save

Yarn

yarn add fecha

Use it

Formatting

format accepts a Date object (or timestamp) and a string format and returns a formatted string. See below for available format tokens.

Note: format will throw an error when passed invalid parameters

import { format } from 'fecha';

type format = (date: Date, format?: string, i18n?: I18nSettings) => str;

// Custom formats
format(new Date(2015, 10, 20), 'dddd MMMM Do, YYYY'); // 'Friday November 20th, 2015'
format(new Date(1998, 5, 3, 15, 23, 10, 350), 'YYYY-MM-DD hh:mm:ss.SSS A'); // '1998-06-03 03:23:10.350 PM'

// Named masks
format(new Date(2015, 10, 20), 'isoDate'); // '2015-11-20'
format(new Date(2015, 10, 20), 'mediumDate'); // 'Nov 20, 2015'
format(new Date(2015, 10, 20, 3, 2, 1), 'isoDateTime'); // '2015-11-20T03:02:01-05:00'
format(new Date(2015, 2, 10, 5, 30, 20), 'shortTime'); // '05:30'

// Literals
format(new Date(2001, 2, 5, 6, 7, 2, 5), '[on] MM-DD-YYYY [at] HH:mm'); // 'on 03-05-2001 at 06:07'

View on Github

10 - Date-fns: Modern JavaScript date utility library.

date-fns provides the most comprehensive, yet simple and consistent toolset for manipulating JavaScript dates in a browser & Node.js.

It's like Lodash for dates

  • It has 200+ functions for all occasions.
  • Modular: Pick what you need. Works with webpack, Browserify, or Rollup and also supports tree-shaking.
  • Native dates: Uses existing native type. It doesn't extend core objects for safety's sake.
  • Immutable & Pure: Built using pure functions and always returns a new date instance.
  • TypeScript & Flow: Supports both Flow and TypeScript
  • I18n: Dozens of locales. Include only what you need.
  • and many more benefits
import { compareAsc, format } from 'date-fns'

format(new Date(2014, 1, 11), 'yyyy-MM-dd')
//=> '2014-02-11'

const dates = [
  new Date(1995, 6, 2),
  new Date(1987, 1, 11),
  new Date(1989, 6, 10),
]
dates.sort(compareAsc)
//=> [
//   Wed Feb 11 1987 00:00:00,
//   Mon Jul 10 1989 00:00:00,
//   Sun Jul 02 1995 00:00:00
// ]

The library is available as an npm package. To install the package run:

npm install date-fns --save
# or with yarn
yarn add date-fns

View on Github

Thank you for following this article.

Related videos:

Javascript Date Library That Will Blow Your Mind

#javascript #timezone 

10 Popular JavaScript Date Libraries
Dexter  Goodwin

Dexter Goodwin

1661867652

Reduce Moment-timezone Data Size for A Webpack Build

moment-timezone-data-webpack-plugin 

Oof, that’s a clunky name, but at least it’s descriptive.

This is a plugin for webpack which reduces data for moment-timezone.

Why is this needed?

Moment Timezone is a comprehensive library for working with time zones in JavaScript. But that comprehensiveness comes with a file size cost. The full time zone data file is 903KiB raw, or 36KiB minified and gzipped (as of moment-timezone version 0.5.23).

That’s a lot of data to send to someone’s browser, especially if you don’t need all of it. Some of the time zones have data dating back to the 19th century. Thankfully there is an API to produce a custom data bundle containing only the time zone definitions you require.

Unfortunately, if you’re building your project with webpack, you don’t get to use a custom data bundle. A webpack build uses the Node.js version of moment-timezone, which automatically includes all the time zone data. Even if you configure Moment Timezone to use a custom data bundle at run-time, the full data file will still be present in your JavaScript bundle.

This plugin allows you to configure which time zone data you want. Any unwanted data is then automatically stripped from the compiled JS bundle at build time.

Use it in combination with the moment-locales-webpack-plugin to further reduce the compiled JS bundle size.

Example

Take a super-simple file which does nothing more than require('moment-timezone'). Building this with webpack in production mode results in over 1 MiB of minified JS code.

What if you only need the default English locale, and time zone data for Australia and New Zealand from 2018 to 2028? (This is a realistic scenario from a recent project.)

Running webpack in production mode results in the following file sizes:

ConfigurationRaw sizeGzipped
Default1164 KiB105 KiB
Strip locales959 KiB (~82%)56 KiB (~53%)
Strip tz data265 KiB (~23%)69 KiB (~66%)
Strip locales & tz data60 KiB (~5%)20 KiB (~19%)

(Testing done with webpack@4.28.3, moment@2.23.0, moment-timezone@0.5.23.)

Even if you still need all the time zones available, reducing the data to a much smaller date range can produce significant file size savings. Building the above example file with data for all zones from 2018 to 2028 produces a file size of 288KiB, or 74KiB gzipped.

⚠️ Make sure you know what you’re doing ❗️️

Dealing with time zones can be tricky, and bugs can pop up in unexpected places. That’s doubly true when you’re auto-removing data at build time. When using this plugin, make absolutely sure that you won’t need the data you’re removing.

For example, if you know for certain that your web site/application...

  1. ...will never deal with past dates & times earlier than a certain point (e.g. the launch date of the application).
  2. ...will never deal with future dates & times beyond a certain point (e.g. details of a specific event).
    • It’s (relatively) safe to remove any data beyond that date (using the endYear option).
  3. ...will only deal with a fixed set of time zones (e.g. rendering times relative to a set of physical buildings in a single country).

However, if you’re allowing users to choose their time zone preference — with no theoretical limit on the range of dates you’ll handle — then you’re going to need all the data you can get.

If you’re in doubt about whether to include some data, err on the side of caution and include it.

Usage

Installation

Using npm:

npm install --save-dev moment-timezone-data-webpack-plugin

Or using yarn:

yarn add --dev moment-timezone-data-webpack-plugin

Configuration

Add the plugin to your webpack config file:

const MomentTimezoneDataPlugin = require('moment-timezone-data-webpack-plugin');

module.exports = {
  plugins: [
    new MomentTimezoneDataPlugin({
      // options
    }),
  ]
};

Plugin options

There are four available options to filter the time zone data. At least one option must be provided.

  • startYear (integer) — Only include data from this year onwards.
  • endYear (integer) — Only include data up to (and including) this year.
  • matchZones — Only include data for time zones with names matching this value. matchZones can be any of these types:
    • string — Include only this zone name as an exact match (e.g. 'Australia/Sydney').
    • regexp — Include zones with names matching the regular expression (e.g. /^Australia\//).
    • array (of the above types) — Include zones matching any of the values of the array. Each value can be a string or a regular expression, which will be matched following the rules above.
  • matchCountries — Only include data for time zones associated with specific countries, as determined by Moment Timezone’s zonesForCountry() API. matchCountries works with ISO 3166 2-letter country codes, and can be any of these types:
    • string — Include zones for this country code as an exact match (e.g. 'AU').
    • regexp — Include zones for country codes matching the regular expression (e.g. /^A|NZ/).
    • array (of the above types) — Include zones for country codes matching any of the values of the array. Each value can be a string or a regular expression, which will be matched following the rules above.

NOTE: The matchCountries option will only work when used with moment-timezone version 0.5.28 or later. If this option is used with a non-compliant version of moment-timezone, an error will be thrown.

All filtering options are AND (a.k.a. conjunction) filters — that is, they become more restrictive as each one is applied. Only zone data that match all the provided filters will be added to the final output. For this reason, it’s probably safer to provide only one of matchZones or matchCountries; providing both is allowed, but you may not get the results you expect.

There are also some non-filtering options that can be provided to configure other behaviour around file locations.

  • cacheDir (string) — A path where the generated files will be cached. If not provided, the files will be cached in an automatically-generated location.
  • momentTimezoneContext (regexp) — A regexp matching a context where moment-timezone is located. The timezone file will be replaced only if it is located in this context. Other instances of the timezone file out of this context will not be touched. This is useful in case you are using a version stored outside of node_modules (e.g. if module or vendor directory is vendor\moment-timezone the context could be matched for example with vendor[\\/]moment-timezone$). Defaults to /node_modules[\\/]moment-timezone$/.

Version support

This plugin has been tested with and officially supports the following dependencies:

  • Node.js 8 or higher
  • webpack 4 and 5
  • moment-timezone v0.1.0 or higher

It theoretically supports older versions of webpack (as it uses built-in webpack plugins internally), but this hasn’t been tested.

Examples

All zones, with a limited date range

const currentYear = new Date().getFullYear();
const plugin = new MomentTimezoneDataPlugin({
  startYear: currentYear - 2,
  endYear: currentYear + 10,
});

All data for a specific zone

const plugin = new MomentTimezoneDataPlugin({
  matchZones: 'America/New_York',
});

All data for a specific country

const plugin = new MomentTimezoneDataPlugin({
  // Includes 'Pacific/Auckland' and 'Pacific/Chatham'
  matchCountries: 'NZ',
});

Limited data for a set of zones (single regular expression)

const plugin = new MomentTimezoneDataPlugin({
  matchZones: /Europe\/(Belfast|London|Paris|Athens)/,
  startYear: 2000,
  endYear: 2030,
});

Limited data for a set of zones (array of values)

const plugin = new MomentTimezoneDataPlugin({
  matchZones: [/^Australia/, 'Pacific/Auckland', 'Etc/UTC'],
  startYear: 2000,
  endYear: 2030,
});

Limited data for a set of countries

const plugin = new MomentTimezoneDataPlugin({
  matchCountries: ['US', 'CA'],
  startYear: 2000,
  endYear: 2030,
});

Download Details:

Author: Gilmoreorless
Source Code: https://github.com/gilmoreorless/moment-timezone-data-webpack-plugin 
License: MIT License 

#javascript #timezone #webpack 

Reduce Moment-timezone Data Size for A Webpack Build
Royce  Reinger

Royce Reinger

1658985060

Dialable: A Ruby Gem That Provides Parsing & Output Of (NANP)

dialable

A gem that provides parsing and output of phone numbers according to NANPA standards.

This gem does not provide a validation for Rails.

Phone numbers are not a big deal if you can validate the input at the time you've got a human right there. My enterprise tends not to have that ability, as we receive large files from clients with little or no validation done. Rather than abandon #s which don't validate, I wrote this to parse and normalize a string into a standard NANP phone number, possibly including an extension.

Usage and Features

$ irb
>> require "dialable"
>> pn = Dialable::NANP.parse("+1(800)555-1212 ext 1234")
>> puts pn.to_s         # Pretty output
800-555-1212 x1234
>> puts pn.to_digits    # Address book friendly
8005551212 x1234
>> puts pn.to_dialable  # PBX friendly
8005551212
>> puts pn.extension
1234

Timezones and Timezone relative offsets

For v1.0.0, the timezone syntax from dialable has changed to output tzinfo compatible names.

Also, pn.timezones and pn.relative_timezones should do the right thing.

Data

The YAML file with the valid area codes and easily recognizable codes (like 911) can get out of date. To update your own copy, run:

cd $(dirname $(gem which dialable)) ; cd ..
ruby ./support/make_yaml_nanpa.rb > data/dialable/nanpa.yaml

References

Author: Chorn
Source Code: https://github.com/chorn/dialable 
License: MIT license

#ruby #location #timezone 

Dialable: A Ruby Gem That Provides Parsing & Output Of (NANP)
Bongani  Ngema

Bongani Ngema

1645560180

Tz-format: Format A Date with Timezone

tz-format

Format a date with timezone: 2015-11-30T10:40:35+01:00

Install

$ npm install --save tz-format

Usage

const format = require('tz-format');

format();
//=> '2015-11-30T10:40:35+01:00'

format(0);
//=> '2015-11-30T09:40:35+00:00'

format(new Date());
//=> '2015-11-30T10:40:35+01:00'

format(new Date(), 0);
//=> '2015-11-30T09:40:35+00:00'

format(new Date(2015, 11, 25, 11, 0, 0, 0), -1);
//=> '2015-12-25T09:00:00-01:00'

API

format([date], [offset])

input

Type: date
Default: new Date()

Date to be formatted.

offset

Type: number
 

Offset from UTC in hours.

Author: Samverschueren
Source Code: https://github.com/samverschueren/tz-format 
License: MIT License

#javascript #node #timezone 

Tz-format: Format A Date with Timezone
Elian  Harber

Elian Harber

1644461700

A Python module that tries to figure out what your local timezone is

tzlocal

API CHANGE!

With version 3.0 of tzlocal, tzlocal no longer returned pytz objects, but zoneinfo objects, which has a different API. Since 4.0, it now restored partial compatibility for pytz users through Paul Ganssle's pytz_deprecation_shim.

tzlocal 4.0 also adds an official function get_localzone_name() to get only the timezone name, instead of a timezone object. On unix, it can raise an error if you don't have a timezone name configured, where get_localzone() will succeed, so only use that if you need the timezone name.

4.0 also adds way more information on what is going wrong in your configuration when the configuration files are unclear or contradictory.

Info

This Python module returns a tzinfo object (with a pytz_deprecation_shim, for pytz compatibility) with the local timezone information, under Unix and Windows.

It requires Python 3.6 or later, and will use the backports.tzinfo package, for Python 3.6 to 3.8.

This module attempts to fix a glaring hole in the pytz and zoneinfo modules, that there is no way to get the local timezone information, unless you know the zoneinfo name, and under several Linux distros that's hard or impossible to figure out.

With tzlocal you only need to call get_localzone() and you will get a tzinfo object with the local time zone info. On some Unices you will still not get to know what the timezone name is, but you don't need that when you have the tzinfo file. However, if the timezone name is readily available it will be used.

Supported systems

These are the systems that are in theory supported:

  • Windows 2000 and later
  • Any unix-like system with a /etc/localtime or /usr/local/etc/localtime

If you have one of the above systems and it does not work, it's a bug. Please report it.

Please note that if you are getting a time zone called local, this is not a bug, it's actually the main feature of tzlocal, that even if your system does NOT have a configuration file with the zoneinfo name of your time zone, it will still work.

You can also use tzlocal to get the name of your local timezone, but only if your system is configured to make that possible. tzlocal looks for the timezone name in /etc/timezone, /var/db/zoneinfo, /etc/sysconfig/clock and /etc/conf.d/clock. If your /etc/localtime is a symlink it can also extract the name from that symlink.

If you need the name of your local time zone, then please make sure your system is properly configured to allow that.

If your unix system doesn't have a timezone configured, tzlocal will default to UTC.

Usage

Load the local timezone:

>>> from tzlocal import get_localzone
>>> tz = get_localzone()
>>> tz
<DstTzInfo 'Europe/Warsaw' WMT+1:24:00 STD>

Create a local datetime:

>>> from datetime import datetime
>>> dt = datetime(2015, 4, 10, 7, 22, tzinfo=tz)
>>> dt
datetime.datetime(2015, 4, 10, 7, 22, tzinfo=<DstTzInfo 'Europe/Warsaw' CEST+2:00:00 DST>)

Lookup another timezone with zoneinfo (backports.zoneinfo on Python 3.8 or earlier):

>>> from zoneinfo import ZoneInfo
>>> eastern = ZoneInfo('US/Eastern')

Convert the datetime:

>>> dt.astimezone(eastern)
datetime.datetime(2015, 4, 10, 1, 22, tzinfo=<DstTzInfo 'US/Eastern' EDT-1 day, 20:00:00 DST>)

If you just want the name of the local timezone, use get_localzone_name():

>>> from tzlocal import get_localzone_name
>>> get_localzone_name()
"Europe/Warsaw"

Please note that under Unix, get_localzone_name() may fail if there is no zone configured, where get_localzone() would generally succeed.

Development

To create a development environment, create a virtualenv and make a development installation:

$ virtualenv ve
$ source ve/bin/activation (Win32: .\ve\Scripts\activate)
(ve) $ pip install -e .[test,devenv]

To run tests, just use pytest, coverage is nice as well:

(ve) $ pytest --cov=tzlocal

Maintainer

Contributors

  • Marc Van Olmen
  • Benjamen Meyer
  • Manuel Ebert
  • Xiaokun Zhu
  • Cameris
  • Edward Betts
  • McK KIM
  • Cris Ewing
  • Ayala Shachar
  • Lev Maximov
  • Jakub Wilk
  • John Quarles
  • Preston Landers
  • Victor Torres
  • Jean Jordaan
  • Zackary Welch
  • Mickaël Schoentgen
  • Gabriel Corona
  • Alex Grönholm
  • Julin S
  • Miroslav Šedivý
  • revansSZ
  • Sam Treweek

(Sorry if I forgot someone)

Author: Regebro
Source Code: https://github.com/regebro/tzlocal 
License: MIT License

#python #timezone 

A Python module that tries to figure out what your local timezone is
Lawrence  Lesch

Lawrence Lesch

1642902720

Date: Date() for Humans

date

Date is an english language date parser for node.js and the browser. For examples and demos, see: http://matthewmueller.github.io/date/

Update: date.js now has much better NLP support thanks to @kengz

Installation

On the server or in the browser:

npm install date.js

Standalone:

Standalone is also AMD-compatible

Examples

date('10 minutes from now')
date('in 5 hours')
date('at 5pm')
date('at 12:30')
date('at 23:35')
date('in 2 days')
date('tuesday at 9am')
date('monday at 1:00am')
date('last monday at 1:00am')
date('tomorrow at 3pm')
date('yesterday at 12:30am')
date('5pm tonight')
date('tomorrow at noon')
date('next week tuesday')
date('next week tuesday at 4:30pm')
date('2 weeks from wednesday')
date('tomorrow night at 9')
date('tomorrow afternoon')
date('this morning at 9')
date('at 12:30pm')
date('tomorrow at 9 in the morning')
date('2 years from yesterday at 5pm')
date('last month')
date('2nd of January')
date('1st of March')
date('1 st of March')
date('31st of September 4:00am')
date('1st of January 4:00am')
date('9th of December 4:00am')
date('tomorrow afternoon at 4:30pm 1 month from now')
date('10 seconds ago')
date('1 minute ago')
date('2 hours ago')
date('5 weeks ago')
date('2 months ago')
date('1 year ago')
date('an hour later')
date('2w from wednesday')
date('2nd day of January')
date('two hours later')
date('a fortnight from wednesday')
date('a minute ago')

date('at 12:30')
date('at 12.30')
date('tuesday at 9')
date('tomorrow at 15')

API

date(str, [offset])

Create a Date from a str. You may also supply an optional offset to the starting date. offset defaults to the current date and time.

Tests

To run the tests, you'll need node.js:

npm install
make test

Contributors

 project  : date
 repo age : 2 years, 10 months
 active   : 39 days
 commits  : 87
 files    : 17
 authors  :
    27  Matt Mueller       31.0%
    12  Bulkan Evcimen     13.8%
     8  kengz              9.2%
     3  Eero Norri         3.4%
     2  thomas             2.3%
     2  Patrick Stadler    2.3%
     1  Christopher Blum   1.1%
     1  Federico Rampazzo  1.1%
     1  Timothy Cyrus      1.1%
     1  chencheng          1.1%
     1  HipsterBrown       1.1%
     1  Jimmy Gaussen      1.1%

Author: MatthewMueller
Source Code: https://github.com/MatthewMueller/date 
License: 

#javascript #timezone 

Date: Date() for Humans
Lawrence  Lesch

Lawrence Lesch

1642895280

Timezone-js: Timezone-enabled JavaScript Date object

TimezoneJS.Date

A timezone-enabled, drop-in replacement for the stock JavaScript Date. The timezoneJS.Date object is API-compatible with JS Date, with the same getter and setter methods -- it should work fine in any code that works with normal JavaScript Dates.

Mailing list

Overview

The timezoneJS.Date object gives you full-blown timezone support, independent from the timezone set on the end-user's machine running the browser. It uses the Olson zoneinfo files for its timezone data.

The constructor function and setter methods use proxy JavaScript Date objects behind the scenes, so you can use strings like '10/22/2006' with the constructor. You also get the same sensible wraparound behavior with numeric parameters (like setting a value of 14 for the month wraps around to the next March).

The other significant difference from the built-in JavaScript Date is that timezoneJS.Date also has named properties that store the values of year, month, date, etc., so it can be directly serialized to JSON and used for data transfer.

Setup

This section shows the most common way of setting up timezone-js. In the 'Customizing' section below you can find alternative approaches.

First you'll need to include the code on your page. Both timezoneJS.Date, and the supporting code it needs in timezoneJS.timezone are bundled in the date.js file in src directory. Include the code on your page with a normal JavaScript script include, like so:

<script type="text/javascript" src="/js/timezone-js/src/date.js">

Next you'll need the Olson time zone files -- timezoneJS.Date uses the raw Olson data to calculate timezone offsets. The Olson region files are simple, structured text data, which download quickly and parse easily. (They also compress to a very small size.)

Here is an example of how to get the Olson time zone files:

##!/bin/bash

# NOTE: Run from your webroot

# Create the /tz directory
mkdir tz

# Download the latest Olson files
curl ftp://ftp.iana.org/tz/tzdata-latest.tar.gz -o tz/tzdata-latest.tar.gz

# Expand the files
tar -xvzf tz/tzdata-latest.tar.gz -C tz

# Optionally, you can remove the downloaded archives.
rm tz/tzdata-latest.tar.gz

Then you'll need to make the files available to the timezoneJS.timezone code, and initialize the code to parse your default region. (This will be North America if you don't change it). No sense in downloading and parsing timezone data for the entire world if you're not going to be using it.

Put your directory of Olson files somewhere under your Web server root, and point timezoneJS.timezone.zoneFileBasePath to it. Then call the init function. Your code will look something like this:

timezoneJS.timezone.zoneFileBasePath = '/tz';
timezoneJS.timezone.init({ callback: cb });

If you use timezoneJS.Date with Fleegix.js, jQuery or jQuery-compatible libraries (like Zepto.js), there's nothing else you need to do -- timezones for North America will be loaded and parsed on initial page load, and others will be downloaded and parsed on-the-fly, as needed. If you want to use this code with some other JavaScript toolkit, you'll need to overwrite your own transport method by setting timezoneJS.timezone.transport = someFunction method. Take a look at test-utils.js in spec for an example.

NOTE: By default init() is async so you'll need to specify a callback function such as init({ callback: cb }). Otherwise set init({ async: false }) to turn off async.

Usage

The timezoneJS.Date constructor is compatible to the normal JavaScript Date constructor, but additional allows to pass an optional tz (timezone). In the following cases the passed date/time is unambiguous:

timezoneJS.Date(millis, [tz])
timezoneJS.Date(Date, [tz])
timezoneJS.Date(dt_str_tz, [tz])

dt_str_tz is a date string containing timezone information, i.e. containing Z, T or a timezone offset matching the regular expression /[+-][0-9]{4}/ (e.g. +0200). The one-stop shop for cross-browser JavaScript Date parsing behavior provides detailed information about JavaScript date formats.

In the following cases the date is assumed to be a date in timezone tz or a locale date if tz is not provided:

timezoneJS.Date(year, mon, day, [hour], [min], [second], [tz])
timezoneJS.Date(dt_str, [tz])

dt_str is a date string containing no timezone information.

Examples

Create a timezoneJS.Date the same way as a normal JavaScript Date, but append a timezone parameter on the end:

var dt = new timezoneJS.Date('10/31/2008', 'America/New_York');
var dt = new timezoneJS.Date(2008, 9, 31, 11, 45, 'America/Los_Angeles');

Naturally enough, the getTimezoneOffset method returns the timezone offset in minutes based on the timezone you set for the date.

// Pre-DST-leap
var dt = new timezoneJS.Date(2006, 9, 29, 1, 59, 'America/Los_Angeles');
dt.getTimezoneOffset(); => 420
// Post-DST-leap
var dt = new timezoneJS.Date(2006, 9, 29, 2, 0, 'America/Los_Angeles');
dt.getTimezoneOffset(); => 480

Just as you'd expect, the getTime method gives you the UTC timestamp for the given date:

var dtA = new timezoneJS.Date(2007, 9, 31, 10, 30, 'America/Los_Angeles');
var dtB = new timezoneJS.Date(2007, 9, 31, 12, 30, 'America/Chicago');
// Same timestamp
dtA.getTime(); => 1193855400000
dtB.getTime(); => 1193855400000

You can set (or reset) the timezone using the setTimezone method:

var dt = new timezoneJS.Date('10/31/2006', 'America/Juneau');
dt.getTimezoneOffset(); => 540
dt.setTimezone('America/Chicago');
dt.getTimezoneOffset(); => 300
dt.setTimezone('Pacific/Honolulu');
dt.getTimezoneOffset(); => 600

The getTimezone method tells you what timezone a timezoneJS.Date is set to:

var dt = new timezoneJS.Date('12/27/2010', 'Asia/Tokyo');
dt.getTimezone(); => 'Asia/Tokyo'

You can use getTimezoneAbbreviation method to get timezone abbreviation:

var dt = new timezoneJS.Date('10/31/2008', 'America/New_York');
dt.getTimezoneAbbreviation(); => 'EDT'

Customizing

If you don't change it, the timezone region that loads on initialization is North America (the Olson 'northamerica' file). To change that to another reqion, set timezoneJS.timezone.defaultZoneFile to your desired region, like so:

timezoneJS.timezone.zoneFileBasePath = '/tz';
timezoneJS.timezone.defaultZoneFile = 'asia';
timezoneJS.timezone.init();

If you want to preload multiple regions, set it to an array, like this:

timezoneJS.timezone.zoneFileBasePath = '/tz';
timezoneJS.timezone.defaultZoneFile = ['asia', 'backward', 'northamerica', 'southamerica'];
timezoneJS.timezone.init();

By default the timezoneJS.Date timezone code lazy-loads the timezone data files, pulling them down and parsing them only as needed.

For example, if you go with the out-of-the-box setup, you'll have all the North American timezones pre-loaded -- but if you were to add a date with a timezone of 'Asia/Seoul,' it would grab the 'asia' Olson file and parse it before calculating the timezone offset for that date.

You can change this behavior by changing the value of timezoneJS.timezone.loadingScheme. The three possible values are:

  1. timezoneJS.timezone.loadingSchemes.PRELOAD_ALL -- this will preload all the timezone data files for all reqions up front. This setting would only make sense if you know your users will be using timezones from all around the world, and you prefer taking the up-front load time to the small on-the-fly lag from lazy loading.
  2. timezoneJS.timezone.loadingSchemes.LAZY_LOAD -- the default. Loads some amount of data up front, then lazy-loads any other needed timezone data as needed.
  3. timezoneJS.timezone.loadingSchemes.MANUAL_LOAD -- Preloads no data, and does no lazy loading. Use this setting if you're loading pre-parsed JSON timezone data.

Ready-made tzdata NPM modules

If you use NPM, and you want to load the time zone data synchronously, you can use one or more of the tzdata* NPM modules. That way, you do not have to download the IANA zone files manually, you can just run npm update to get the latest data.

The tzdata module contains all time zones. There are other modules, e.g. tzdata-northamerica that contain subsets of the zones.

First, install timezone-js and one or more of the tzdata modules.

npm install timezone-js tzdata

Then, initialize timezone-js with the data:

var timezoneJS = require("timezone-js");
var tzdata = require("tzdata");

var _tz = timezoneJS.timezone;
_tz.loadingScheme = _tz.loadingSchemes.MANUAL_LOAD;
_tz.loadZoneDataFromObject(tzdata);

var dt = new timezoneJS.Date(2006, 9, 29, 1, 59, 'America/Los_Angeles');

Pre-Parsed JSON Data

If you know beforehand what specific cities your users are going to be using, you can reduce load times specifically by creating a pre-parsed JSON data file containing only the timezone info for those specific cities.

The src directory contains 2 command-line JavaScript scripts that can generate this kind of JSON data:

  • node-preparse.js: Uses Node to preparse and populate data.
  • preparse.js: This script requires the Rhino (Java) JavaScript engine to run, since the stock SpiderMonkey (C) engine doesn't come with file I/O capabilities.

Use the script like this:

rhino preparse.js zoneFileDirectory [exemplarCities] > outputfile.json

Or:

node node-preparse.js zoneFileDirectory [exemplarCities] > outputfile.json

The first parameter is the directory where the script can find the Olson zoneinfo files. The second (optional) param should be a comma-delimited list of timzeone cities to create the JSON data for. If that parameter isn't passed, the script will generate the JSON data for all the files.

rhino preparse.js olson_files \
"Asia/Tokyo, America/New_York, Europe/London" \
> major_cities.json

rhino preparse.js olson_files > all_cities.json

Or:

node node-preparse.js olson_files \
"Asia/Tokyo, America/New_York, Europe/London" \
> major_cities.json

node node-preparse.js olson_files > all_cities.json

Once you have your file of JSON data, set your loading scheme to timezoneJS.timezone.loadingSchemes.MANUAL_LOAD, and load the JSON data with loadZoneJSONData, like this:

var _tz = timezoneJS.timezone;
_tz.loadingScheme = _tz.loadingSchemes.MANUAL_LOAD;
_tz.loadZoneJSONData('/major_cities.json', true);

Since the limited set of data will be much smaller than any of the zoneinfo files, and the JSON data is deserialized with eval or JSON.parse, this method is significantly faster than the default setup. However, it only works if you know beforehand exactly what timezones you want to use.

Compressing

The Olson timezone data files are simple, space- and linefeed-delimited data. The abundance of whitespace means they compress very, very well.

If you plan to use timezoneJS.Date in a production Web app, it's highly recommended that you first strip the copious comments found in every Olson file, and serve compressed versions of the files to all browsers that can handle it. (Note that IE6 reports itself as able to work with gzipped data, but has numerous problems with it.)

Just to give you an idea of the difference -- merely stripping out the comments from the 'northamerica' file reduces its size by two-thirds -- from 103K to 32K. Gzipping the stripped file reduces it down to 6.5K -- probably smaller than most of the graphics in your app.

The src directory has a sample Ruby script that you can use to strip comments from Olson data files.

Development

This project use Jake to build. In order to see available tasks, do jake -T. The build sequence is:

  • jake test:init: Download and extract tz files to lib/tz.
  • jake test: Run jasmine-node.

Feel free to fork and modify at your own will. The source code is annotated and doc can be generated with jake doc.

Author: Mde
Source Code: https://github.com/mde/timezone-js 
License:

#javascript #timezone 

Timezone-js: Timezone-enabled JavaScript Date object
Lawrence  Lesch

Lawrence Lesch

1642880340

Moment-timezone: Timezone support for moment.js

Moment Timezone

IANA Time zone support for Moment.js

Project Status

Moment-Timezone is an add-on for Moment.js. Both are considered legacy projects, now in maintenance mode. In most cases, you should choose a different library.

For more details and recommendations, please see Project Status in the Moment docs.

Thank you.

Resources

Examples

var june = moment("2014-06-01T12:00:00Z");
june.tz('America/Los_Angeles').format('ha z'); // 5am PDT
june.tz('America/New_York').format('ha z');    // 8am EDT
june.tz('Asia/Tokyo').format('ha z');          // 9pm JST
june.tz('Australia/Sydney').format('ha z');    // 10pm EST

var dec = moment("2014-12-01T12:00:00Z");
dec.tz('America/Los_Angeles').format('ha z');  // 4am PST
dec.tz('America/New_York').format('ha z');     // 7am EST
dec.tz('Asia/Tokyo').format('ha z');           // 9pm JST
dec.tz('Australia/Sydney').format('ha z');     // 11pm EST

Author: Moment
Source Code: https://github.com/moment/moment-timezone
License: MIT License

#javascript #timezone 

Moment-timezone: Timezone support for moment.js

Time Zone Database and Time Zone Aware DateTime Object for Dart

TimeZone

This package provides the IANA time zone database and time zone aware DateTime class, TZDateTime.

The current time zone database version is 2021a. See the announcement for details.

You can update to the current IANA time zone database by running tool/refresh.sh.

Initialization

TimeZone objects require time zone data, so the first step is to load one of our time zone databases.

We provide three different APIs to load a database: one which is embedded into a Dart library, one for browsers, and one for standalone environments.

Database variants

We offer three different variants of the IANA database:

  • default: doesn't contain deprecated and historical zones with some exceptions like "US/Eastern" and "Etc/UTC"; this is about 75% the size of the all database.
  • all: contains all data from the IANA time zone database.
  • 10y: default database truncated to contain historical data from 5 years ago until 5 years in the future; this database is about 25% the size of the default database.

Initialization from Dart library

This is the recommended way to initialize a time zone database for non-browser environments. Each Dart libary found in lib/data, for example lib/data/latest.dart, contains a single no-argument function, initializeTimeZones.

import 'package:timezone/data/latest.dart' as tz;
void main() {
  tz.initializeTimeZones();
}

To initialize the all database variant, import 'package:timezone/data/latest_all.dart'. To initialize the 10y database variant, import 'package:timezone/data/latest_10y.dart'.

Initialization for browser environment

Import package:timezone/browser.dart library and run async function Future initializeTimeZone([String path]).

import 'package:timezone/browser.dart' as tz;

Future<void> setup() async {
  await tz.initializeTimeZone();
  var detroit = tz.getLocation('America/Detroit');
  var now = tz.TZDateTime.now(detroit);
}

To initialize the all database variant, call initializeTimeZone('packages/timezone/data/latest_all.tzf'). To initialize the 10y database variant, call initializeTimeZone('packages/timezone/data/latest_10y.tzf').

Initialization for standalone environment

Import package:timezone/standalone.dart library and run async function Future initializeTimeZone([String path]).

import 'package:timezone/standalone.dart' as tz;

Future<void> setup() async {
  await tz.initializeTimeZone();
  var detroit = tz.getLocation('America/Detroit');
  var now = tz.TZDateTime.now(detroit);
}

Note: This method likely will not work in a Flutter environment.

To initialize the all database variant, call initializeTimeZone('data/latest_all.tzf'). To initialize the 10y database variant, call initializeTimeZone('data/latest_10y.tzf').

Local Location

By default, when library is initialized, local location will be UTC.

To overwrite local location you can use setLocalLocation(Location location) function.

Future<void> setup() async {
  await tz.initializeTimeZone();
  var detroit = tz.getLocation('America/Detroit');
  tz.setLocalLocation(detroit);
}

API

Library Namespace

The public interfaces expose several top-level functions. It is recommended then to import the libraries with a prefix (the prefix tz is common), or to import specific members via a show clause.

Location

Each location in the database represents a national region where all clocks keeping local time have agreed since 1970. Locations are identified by continent or ocean and then by the name of the location, which is typically the largest city within the region. For example, America/New_York represents most of the US eastern time zone; America/Phoenix represents most of Arizona, which uses mountain time without daylight saving time (DST); America/Detroit represents most of Michigan, which uses eastern time but with different DST rules in 1975; and other entries represent smaller regions like Starke County, Indiana, which switched from central to eastern time in 1991 and switched back in 2006.

The tz database

Get location by Olsen time zone ID

final detroit = tz.getLocation('America/Detroit');

We don't provide any functions to get locations by time zone abbreviations because of the ambiguities.

Alphabetic time zone abbreviations should not be used as unique identifiers for UTC offsets as they are ambiguous in practice. For example, "EST" denotes 5 hours behind UTC in English-speaking North America, but it denotes 10 or 11 hours ahead of UTC in Australia; and French-speaking North Americans prefer "HNE" to "EST".

The tz database

TimeZone

TimeZone objects represents time zone and contains offset, DST flag, and name in the abbreviated form.

var timeInUtc = DateTime.utc(1995, 1, 1);
var timeZone = detroit.timeZone(timeInUtc.millisecondsSinceEpoch);

TimeZone aware DateTime

The TZDateTime class implements the DateTime interface from dart:core, and contains information about location and time zone.

var date = tz.TZDateTime(detroit, 2014, 11, 17);

Converting DateTimes between time zones

To convert between time zones, just create a new TZDateTime object using from constructor and pass Location and DateTime to the constructor.

var localTime = tz.DateTime(2010, 1, 1);
var detroitTime = tz.TZDateTime.from(time, detroit);

This constructor supports any objects that implement DateTime interface, so you can pass a native DateTime object or our TZDateTime.

Listing known time zones

After initializing the time zone database, the timeZoneDatabase top-level member contains all of the known time zones. Examples:

import 'package:timezone/timezone.dart' as tz;
import 'package:timezone/data/latest.dart' as tz;

void main() {
  tz.initializeTimeZones();
  var locations = tz.timeZoneDatabase.locations;
  print(locations.length); // => 429
  print(locations.keys.first); // => "Africa/Abidjan"
  print(locations.keys.last); // => "US/Pacific"
}

Time Zone databases

We are using IANA Time Zone Database to build our databases.

We currently build three different database variants:

  • default (doesn't contain deprecated and historical zones with some exceptions like US/Eastern). 361kb
  • all (contains all data from the IANA time zone database). 443kb
  • 10y (default database that contains historical data from the last and future 5 years). 85kb

Updating Time Zone databases

Script for updating Time Zone database, it will automatically download the IANA time zone database and compile into our native format.

$ chmod +x tool/refresh.sh
$ tool/refresh.sh

Use this package as a library

Depend on it

Run this command:

With Dart:

 $ dart pub add timezone

With Flutter:

 $ flutter pub add timezone

This will add a line like this to your package's pubspec.yaml (and run an implicit dart pub get):

dependencies:
  timezone: ^0.8.0

Alternatively, your editor might support dart pub get or flutter pub get. Check the docs for your editor to learn more.

Import it

Now in your Dart code, you can use:

import 'package:timezone/timezone.dart'; 

Download Details:

Author: srawlins

Source Code: https://github.com/srawlins/timezone

#timezone #dart 

Time Zone Database and Time Zone Aware DateTime Object for Dart
坂本  健一

坂本 健一

1633583160

PythonでのCeleryを使用した非同期タスク

従来のWebアプリケーションは本質的に同期しています。 ユーザーはブラウザーに表示されるWebインターフェースを操作し、ブラウザーはそのユーザー操作に基づいてサーバーに要求を返し、サーバーはユーザーの新しい表示でそれらの要求に応答します。

今日、状況は変化しました。現代のWebサイトは、数十万の訪問者からの要求を処理する必要があります。これらの要求にデータベースまたはWebサービスとの対話が含まれる場合、応答時間が長くなり、何千もの訪問者が同じリソースにアクセスしている場合、Webサイトのパフォーマンスが大幅に低下する可能性があります。 ここで非同期Webが助けになります。

非同期性を選択したときに把握できる利点のいくつかを次に示します。

  • より多くのリクエストを処理する機能
  • I / Oバウンドメソッドの並列実行。
  • 応答性が向上しました。

範囲

このチュートリアルでは、新しい要求に応答するWebサーバーの機能を制限する長時間実行タスクを処理するWebアプリケーションを構築するときに発生する一般的な落とし穴の1つを克服する方法を説明します。

簡単な解決策は、これらの長時間実行タスクをバックグラウンドで非同期に、別のスレッドまたはプロセス内で実行し、Webサーバーを解放することです。

Redis、Flask、Celery、SocketIOなどのいくつかのコンポーネントを活用して、長時間実行されるタスクの実行をオフロードし、完了したら、クライアントにそのステータスを示すプッシュ通知を送信します。

このチュートリアルでは、コルーチンを使用してコードを同時に実行できるasyncioPythonの組み込みライブラリについては説明していません。

前提条件

要件が満たされると、次のコンポーネントが機能します。

Redis:は、オープンソースの高度なKey-Valueストアであり、高性能でスケーラブルなWebアプリケーションを構築するための適切なソリューションです。それを際立たせる3つの主な特徴があります:

Redisはデータベースを完全にメモリに保持し、永続性のためにのみディスクを使用します。

多くのKey-Valueデータストアと比較すると、Redisには比較的豊富なデータ型のセットがあります。

  • Redisは、任意の数のスレーブにデータを複製できます。

Redisのインストールは、このチュートリアルの範囲外です。ただし、Windowsマシンにインストールするには、このクイックガイドに従うことをお勧めします。

LinuxまたはmacOSを使用している場合は、以下のコマンドのいずれかを実行すると、Redisがセットアップされます。

Ubuntu / Debian:

$ sudo apt-get install redis-server

マックOS:

$ brew install redis
$ brew services start redis

注意: このチュートリアルでは、Redisバージョン3.0.504を使用しています

セロリ:Pythonの世界で最も人気のあるバックグラウンドジョブマネージャーの1人です。リアルタイム操作に重点を置いていますが、スケジューリングもサポートしています。RedisやRabbitMQなどのいくつかのメッセージブローカーと互換性があり、プロデューサーとコンシューマーの両方として機能できます。

requirements.txt ファイルにCeleryをインストールし ます。

注意: このチュートリアルでは、Celeryバージョン4.4.7を使用しています。

  • Socket.IO:リアルタイムWebアプリケーション用のJavaScriptライブラリです。これにより、Webクライアントとサーバー間のリアルタイムの双方向通信が可能になります。これには、ブラウザで実行されるクライアント側ライブラリとサーバー側ライブラリの2つの部分があります。 
  • Flask:Pythonで記述されたWebアプリケーションのマイクロフレームワーク。

食欲をそそる

このチュートリアルでは、スキャフォールディング手法を採用し、同期通信と非同期通信の違い、および非同期通信のバリエーションを理解するために、一連のさまざまなシナリオについて説明します。

すべてのシナリオはFlaskフレームワーク内で提示されます。ただし、それらのほとんどは他のPythonフレームワーク(Django、Pyramid)に簡単に移植できます。

このチュートリアルに興味をそそられ、すぐにコードに飛び込みたいと思う 場合は、この記事で使用されているコードについて、このGithubリポジトリにアクセス してください。

アプリケーションスケルトンの作成

私たちのアプリケーションは以下で構成されます:

  • app_sync.py 同期通信を紹介するプログラム 。
  • app_async1.py クライアントがポーリングメカニズムを使用してサーバー側プロセスのフィードバックを要求する可能性がある非同期サービス呼び出しを示すプログラム 。
  • app_async2.py クライアントへの自動フィードバックを伴う非同期サービス呼び出しを示すプログラム 。
  • app_async3.py クライアントへの自動フィードバックを伴う、スケジュール後の非同期サービス呼び出しを示すプログラム 。

セットアップに飛び込みましょう。もちろん 、システムにPython3をインストールする必要があり ます。私は必要なライブラリをインストールする仮想環境を使用します(そしてあなたも間違いなくそうするべきです):

$ python -m venv async-venv
$ source async-venv/bin/activate

名前の付いたファイルを作成し、 requirements.txt その中に次の行を追加します。

Flask==1.1.2
Flask-SocketIO==5.0.1
Celery==4.4.7
redis==3.5.3
gevent==21.1.2
gevent-websocket==0.10.1
flower==0.9.7

今それらをインストールします:

$ pip install -r requirements.txt

このチュートリアルを終了すると、フォルダー構造は次のようになります。

プロジェクト構造

それがクリアされたので、実際のコードを書き始めましょう。

まず、アプリケーションの構成パラメータを次のように定義します config.py

#config.py
#Application configuration File
################################

#Secret key that will be used by Flask for securely signing the session cookie
# and can be used for other security related needs
SECRET_KEY = 'SECRET_KEY'

#Map to REDIS Server Port
BROKER_URL = 'redis://localhost:6379'

#Minimum interval of wait time for our task
MIN_WAIT_TIME = 1
#Maximum interval of wait time for our task
MAX_WAIT_TIME = 20

注意:簡潔にするために、これらの構成パラメーターをにハードコーディングしましたが config.py、これらのパラメーターを別のファイル(たとえば.env)に保存することをお勧めします 。

次に、プロジェクトの初期化ファイルを次の場所に作成します init.py

#init.py
from flask import Flask

#Create a flask instance
app = Flask(__name__)
#Loads flask configurations from config.py
app.secret_key = app.config['SECRET_KEY']
app.config.from_object("config")

#Setup the Flask SocketIO integration (Required only for asynchronous scenarios)
from flask_socketio import SocketIO
socketio = SocketIO(app,logger=True,engineio_logger=True,message_queue=app.config['BROKER_URL'])

シナリオ1:同期通信の紹介

コーディングに入る前に、同期通信について簡単に説明します。

同期通信、発呼者がサービスを要求し、完全にサービスを待ち受けます。そのサービスの結果を受け取った場合にのみ、作業を続行します。タイムアウトを定義して、定義された期間内にサービスが終了しない場合、呼び出しは失敗したと見なされ、呼び出し元は続行します。 

同期通信がどのように機能するかを理解するために、専用のウェイターが割り当てられたと想像してください。彼はあなたの注文を受け取り、それをキッチンに届け、そこでシェフがあなたの料理を準備するのを待ちます。この間、ウェイターは何もしていません。

次の図は、同期サービス呼び出しを示しています。

同期通信

同期通信はシーケンシャルタスクに適していますが、同時タスクが多数ある場合、プログラムはスレッドを使い果たし、スレッドが使用可能になるまで新しいタスクを待機させる可能性があります。

それでは、コーディングに取り掛かりましょう。Flaskがレンダリングできるテンプレート(index.html)を作成し、その中に次のHTMLコードを含めます。

templates/index.html

<!DOCTYPE html>
<html>
  <head>
    <title>Synchronicity versus Asynchronicity</title>
    <link rel="stylesheet" href="{{url_for('static',filename='css/materialize.min.css')}}">
    <script src="{{ url_for('static',filename='js/jquery.min.js') }}"></script>
    <script src="{{ url_for('static',filename='js/socket.io.js') }}"></script>
    <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
  </head>
  <body class="container">
    <div class="row">
        <h5>Click to start a post scheduled ansycnhronous task with automatic feedback.</h5>
    </div>
    <div class="card-panel">
      <form method='post' id="runTaskForm" action="/runPSATask">
          <div>
             <input id="duration" name="duration" placeholder="Enter duration in seconds. for example: 30" type="text">
             <label for="duration">Duration</label>
          </div>
          <button style="height:50px;width:600px" type="submit" id="runTask">Run A Post Scheduled Asynchronous Task With Automatic Feedback</button>
      </form>
    </div>
    <div class="row">
        <div id="Messages" class="red-text" style="width:800px; height:400px; overflow-y:scroll;"></div>
    </div>
    <script>
      $(document).ready(function(){
        var namespace='/runPSATask';
        var url = 'http://' + document.domain + ':' + location.port + namespace;
        var socket = io.connect(url);
        socket.on('connect', function() {
                             socket.emit('join_room');
                            });

        socket.on('msg' , function(data) {
                            $("#Messages").prepend('<li>'+data.msg+'</li>');
                          });

        socket.on('status', function(data) {
                            ////alert('socket on status ='+ data.msg);
                            if (data.msg == 'End') {
                                $("#runTask").attr("disabled",false);
                            };
                          });
      });
    </script>
    <script>
      $("#runTask").click(function(e) {
         $("#runTask").attr("disabled",true);
         $("#Messages").empty();
         $.ajax({ type: "Post"
                , url: '/runPSATask'
                , data: $("#runTaskForm").serialize()
                , success: function(data) {
                    $("#Messages").empty();
                    $("#Messages").prepend('<li>The Task ' + data.taskid + ' has been submitted and will execute in ' + data.duration + ' seconds. </li>');
                  }
                });
         e.preventDefault();
         console.log('runPSATask complete');
      });
    </script>
  </body>
</html>

このテンプレートには次のものが含まれます。

  • runTaskルートを使用してサーバーにタスクを送信するボタン/runSyncTask
  • 結果はdividでに配置されMessagesます。

次に、app_sync.pyFlaskアプリケーションを含むというプログラムを作成し、このプログラム内に2つのルートを定義します。

  • "/"Webページをレンダリングします(index.html
  • "/runSyncTask"1〜20秒の乱数を生成し、反復ごとに1秒間スリープするループを実行する、長時間実行中のタスクをシミュレートします。
#app_sync.py
from flask import render_template, jsonify
from random import randint
from init import app
import tasks

#Render the predefined template index.html
@app.route("/",methods=['GET'])
def index():
    return render_template('index.html')

#Defining the route for running A Synchronous Task
@app.route("/runSyncTask",methods=['POST'])
def long_sync_task():
    print("Running","/runSyncTask")
    #Generate a random number between MIN_WAIT_TIME and MAX_WAIT_TIME
    n = randint(app.config['MIN_WAIT_TIME'],app.config['MAX_WAIT_TIME'])
    #Call the function long_sync_task included within tasks.py
    task = tasks.long_sync_task(n=n)
    #Return the random wait time generated
    return jsonify({ 'waittime': n })

if __name__ == "__main__":
    app.run(debug=True)

このチュートリアルで定義されているすべてのタスクのコアロジックは、プログラム内にありますtasks.py

#tasks.py
import time
from celery import Celery
from celery.utils.log import get_task_logger
from flask_socketio import SocketIO
import config

# Setup the logger (compatible with celery version 4)
logger = get_task_logger(__name__)

# Setup the celery client
celery = Celery(__name__)
# Load celery configurations from celeryconfig.py
celery.config_from_object("celeryconfig")

# Setup and connect the socket instance to Redis Server
socketio = SocketIO(message_queue=config.BROKER_URL)

###############################################################################
def long_sync_task(n):
    print(f"This task will take {n} seconds.")
    for i in range(n):
        print(f"i = {i}")
        time.sleep(1)
###############################################################################
@celery.task(name = 'tasks.long_async_task')
def long_async_task(n,session):
    print(f"The task of session {session}  will take {n} seconds.")
    for i in range(n):
        print(f"i = {i}")
        time.sleep(1)
###############################################################################
def send_message(event, namespace, room, message):
    print("Message = ", message)
    socketio.emit(event, {'msg': message}, namespace=namespace, room=room)

@celery.task(name = 'tasks.long_async_taskf')
def long_async_taskf(data):
    room      = data['sessionid']
    namespace = data['namespase']
    n         = data['waittime']

    #Send messages signaling the lifecycle of the task
    send_message('status', namespace, room, 'Begin')
    send_message('msg', namespace, room, 'Begin Task {}'.format(long_async_taskf.request.id))
    send_message('msg', namespace, room, 'This task will take {} seconds'.format(n))

    print(f"This task will take {n} seconds.")
    for i in range(n):
        msg = f"{i}"
        send_message('msg', namespace, room, msg )
        time.sleep(1)

    send_message('msg', namespace, room, 'End Task {}'.format(long_async_taskf.request.id))
    send_message('status', namespace, room, 'End')
###############################################################################
@celery.task(name = 'tasks.long_async_sch_task')
def long_async_sch_task(data):
    room      = data['sessionid']
    namespace = data['namespase']
    n         = data['waittime']

    send_message('status', namespace, room, 'Begin')
    send_message('msg'   , namespace, room, 'Begin Task {}'.format(long_async_sch_task.request.id))
    send_message('msg'   , namespace, room, 'This task will take {} seconds'.format(n))

    print(f"This task will take {n} seconds.")
    for i in range(n):
        msg = f"{i}"
        send_message('msg', namespace, room, msg )
        time.sleep(1)

    send_message('msg'   , namespace, room, 'End Task {}'.format(long_async_sch_task.request.id))
    send_message('status', namespace, room, 'End')
###############################################################################

このセクションでは、このlong_sync_task()関数を同期タスクとしてのみ使用します。

app_sync.pyプログラムを実行して、同期シナリオをテストしてみましょう。

$ python app_sync.py

http://localhost:5000Flaskインスタンスが実行されているリンクにアクセスすると、次の出力が表示されます。

Flaskアプリのホームページ

「同期タスクの実行」ボタンを押して、プロセスが完了するまで待ちます。

同期タスク実行後のホームページ

完了すると、トリガーされたタスクに割り当てられたランダムな時間を通知するメッセージが表示されます。

同時に、サーバーがタスクを実行すると、コンソールに1秒ごとに増分された数値が表示されます。

コンソールに表示されるタスク

シナリオ2:ポーリングメカニズムを使用した非同期サービス呼び出しの表示

このセクションでは、クライアントがポーリングメカニズムを使用してサーバー側プロセスのフィードバックを要求する可能性のある非同期サービス呼び出しを示します。

簡単に言うと、非同期とは、プログラムが特定のプロセスが完了するのを待たずに、関係なく続行することを意味します。

発信者が開始サービスコールが、やるES N結果をオト待ち時間。発信者は、結果を気にせずにすぐに作業を続行します。発信者が結果に関心がある場合は、後で説明するメカニズムがあります。

最も単純な非同期メッセージ交換パターンはファイアアンドフォーゲットと呼ばれ 、メッセージは送信されますがフィードバックは必要ありませんが、フィードバックが必要な場合、クライアントはポーリングメカニズムを介して結果を繰り返し要求することがあります 。

ポーリングは潜在的に高いネットワーク負荷を引き起こすため、お勧めしません。それでも、サービスプロバイダー(サーバー)がクライアントについて知る必要がないという利点があります。

次の図は、シナリオを示しています。

ポーリングメカニズムとの非同期通信非同期通信は、イベントに応答する必要のあるコード(たとえば、待機を伴う時間のかかるI / Oバウンド操作)に適しています。

非同期性を選択すると、システムは同時により多くの要求を処理できるようになり、スループットが向上します。

それでは、コーディングに移りましょう。構成ファイルを使用して、セロリの初期化パラメーターを定義しますceleryconfig.py

#celeryconfig.py
#Celery Configuration parameters
#Map to Redis server
broker_url = 'redis://localhost:6379/0'

#Backend used to store the tasks results
result_backend = 'redis://localhost:6379/0'

#A string identifying the default serialization to use Default json
task_serializer = 'json'
result_serializer = 'json'
accept_content = ['json']

#When set to false the local system timezone is used.
enable_utc = False

#To track the started state of a task, we should explicitly enable it
task_track_started = True

#Configure Celery to use a specific time zone.
#The timezone value can be any time zone supported by the pytz library
#timezone = 'Asia/Beirut'
#enable_utc = True

Flaskがレンダリングできるテンプレートを作成します(index1.html):

<!DOCTYPE html>
<html>
  <head>
    <title>Synchronicity versus Asynchronicity</title>
    <link rel="stylesheet" href="{{url_for('static',filename='css/materialize.min.css')}}">
    <script src="{{ url_for('static',filename='js/jquery.min.js') }}"></script>
    <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
  </head>
  <body class="container">
    <div class="row">
        <h4>Click to start an ansycnhronous task</h4>
    </div>
    <div class="card-panel">
      <form method='post' id="runTaskForm" action="/runAsyncTask">
          <button style="height:50px;width:400px" type="submit" id="runTask">Run An Asynchronous Task</button>
      </form>
      <form method='post' id="getTaskResultForm" action="/getAsyncTaskResult">
          <button style="height:50px;width:400px" type="submit" id="getTaskResult">Get Asynchronous Task Result</button>
      </form>
    </div>
    <div class="row">
        <div id="Messages" class="red-text" style="width:800px; height:400px; overflow-y:scroll;"></div>
    </div>
    <script>
      $("#runTask").click(function(e) {
         $("#runTask").attr("disabled",true);
         $("*").css("cursor","wait");
         $("#Messages").empty();
         $.ajax({ type: "Post"
                , url: '/runAsyncTask'
                , data: $("#runTaskForm").serialize()
                , success: function(data) {
                    $("#runTask").attr("disabled",false);
                    $("*").css("cursor","");
                    $("#Messages").append('The task ' + data.taskid + ' will be executed in asynchronous manner for ' + data.waittime + ' seconds...');
                  }
                });
         e.preventDefault();
         console.log('runAsyncTask complete');
      });
      $("#getTaskResult").click(function(e) {
         var msg = $("#Messages").text();
         var taskid = msg.match("task(.*)will");
         //Get The Task ID from The Messages div and create a Target URL
         var vurl = '/getAsyncTaskResult?taskid=' + jQuery.trim(taskid[1]);
         $.ajax({ type: "Post"
                , url: vurl
                , data: $("#getTaskResultForm").serialize()
                , success: function(data) {
                    $("*").css("cursor","");
                    $("#Messages").append('<p> The Status of the task = ' + data.taskid + ' is ' + data.taskstatus + '</p>');
                  }
                });
         e.preventDefault();
         console.log('getAsyncTaskResult complete');
      });
    </script>
  </body>
</html>

次に、app_async1.pyFlaskアプリを含むプログラムを作成します。

#app_async1.py
from flask import render_template, jsonify, session,request
from random import randint
import uuid
import tasks
from init import app
from celery.result import AsyncResult

@app.route("/",methods=['GET'])
def index():
    # create a unique ID to assign for the asynchronous task
    if 'uid' not in session:
        sid = str(uuid.uuid4())
        session['uid'] = sid
        print("Session ID stored =", sid)
    return render_template('index1.html')

#Run an Asynchronous Task
@app.route("/runAsyncTask",methods=['POST'])
def long_async_task():
    print("Running", "/runAsyncTask")
    #Generate a random number between MIN_WAIT_TIME and MAX_WAIT_TIME
    n = randint(app.config['MIN_WAIT_TIME'],app.config['MAX_WAIT_TIME'])
    sid = str(session['uid'])
    task = tasks.long_async_task.delay(n=n,session=sid)
    #print('taskid',task.id,'sessionid',sid,'waittime',n )
    return jsonify({'taskid':task.id,'sessionid':sid,'waittime':n })

#Get The Result of The Asynchronous Task
@app.route('/getAsyncTaskResult', methods=['GET', 'POST'])
def result():
    task_id = request.args.get('taskid')
    # grab the AsyncResult
    result = AsyncResult(task_id)
    # print the task id
    print("Task ID = ", result.task_id)
    # print the Asynchronous result status
    print("Task Status = ", result.status)
    return jsonify({'taskid': result.task_id, 'taskstatus': result.status})

if __name__ == "__main__":
   app.run(debug=True)

このプログラムには、3つの主要なルートがあります。

  • "/":Webページをレンダリングします(index1.html)。
  • "/runAsyncTask":1〜20秒の乱数を生成する非同期タスクを呼び出してから、反復ごとに1秒間スリープするループを実行します。
  • "/getAsyncTaskResult":受信したタスクIDに基づいて、タスクの状態を収集します。

注意:このシナリオには、SocketIOコンポーネントは含まれていません。 

このシナリオをテストして、次の手順に従ってパスを進めましょう。

  • Redisサーバーを起動します。Windowsでは、Redisがインストールされているフォルダーを見つけて、をダブルクリックしredis-server.exeます。デフォルトのインストールまたはLinux / MacOSの場合は、RedisインスタンスがTCPポート6379で実行されていることを確認してください。
  • Celeryワーカーを起動します。Windowsでは、コマンドプロンプトを開き、プロジェクトフォルダーに移動して、次のコマンドを実行します。
$ async-venv\Scripts\celery.exe worker -A tasks --loglevel=DEBUG --concurrency=1 -P solo -f celery.logs

Linux / MacOSでは、非常によく似ています。

$ async-venv/bin/celery worker -A tasks --loglevel=DEBUG --concurrency=1 -P solo -f celery.logs

これasync-venvが仮想環境の名前であることに注意してください。別の名前を付けた場合は、必ず自分の名前に置き換えてください。セロリが始まると、次の出力が表示されます。セロリが定義したタスク

プログラムで定義されたタスクtasks.pyがCeleryに反映されていることを確認してください。

  • ターミナルウィンドウを開き、メインプログラムを起動します。
$ python app_async1.py​

次に、ブラウザを開いて、次のリンクにアクセスします。 

ポーリングメカニズムアプリとの非同期通信

[非同期タスクの実行]ボタンを押すと、新しいタスクがキューに入れられ、直接実行されます。「メッセージ」セクションに、タスクのIDとその実行時間を示すメッセージが表示されます。

[非同期タスク結果の取得]ボタンを(継続的に)押すと、その特定の時間におけるタスクの状態が収集されます。

セロリタスクの組み込み状態は次のとおりです。

  • PENDING:実行を待機しています。
  • STARTED:タスクが開始されました。
  • SUCCESS:タスクは正常に実行されました。
  • FAILURE:タスクの実行により例外が発生しました。
  • RETRY:タスクは再試行されています。
  • REVOKED:タスクが取り消されました。

ログファイルに含まれているセロリワーカーのログcelery.logsを確認すると、タスクのライフサイクルに気付くでしょう。

セロリログのタスクライフサイクルシナリオ3:自動フィードバックを使用した非同期サービス呼び出しの表示

以前のシナリオに基づいて、タスクの状態を収集するために複数のリクエストを開始することによる煩わしさを軽減するために、サーバーがタスクの状態に関してクライアントを継続的に更新できるようにするソケットテクノロジの組み込みを試みます。

実際、ソケットIOエンジンは、リアルタイムの双方向イベントベースの通信を可能にします。

これがもたらす主な利点は、ネットワークの負荷を軽減し、膨大な数のクライアントに情報を伝達するためにより効率的になることです。

次の図は、シナリオを示しています。

自動フィードバックによる非同期通信

さらに掘り下げる前に、実行する手順について簡単に説明します。

セロリからWebブラウザーにメッセージを送り返すことができるようにするために、以下を活用します。

  • Flask-SocketIOのメッセージキュー機能。これにより、Celeryワーカーがクライアントと通信できるようになります。
  • TのWebSocket接続を可能にするための使いやすいJavaScriptライブラリであるSocket.ioの彼の能力。

データ接続を効果的に管理するために、次の区分化戦略を採用します。

  • "/runAsyncTaskF"このシナリオに名前空間を割り当てます。(名前空間は、単一の共有接続を介してサーバーロジックを分離するために使用されます)。
  • W eは、各ユーザーセッションのための部屋を割り当てます。(部屋は名前空間のサブディビジョンまたはサブチャネルです)。

それでは、コーディングに移りましょう。

  • Flaskがレンダリングできるテンプレートを作成します(index2.html):
<!DOCTYPE html>
<html>
<head>
    <title>Synchronicity versus Asynchronicity</title>
    <link rel="stylesheet" href="{{url_for('static',filename='css/materialize.min.css')}}">
    <script src="{{ url_for('static',filename='js/jquery.min.js') }}"></script>
    <script src="{{ url_for('static',filename='js/socket.io.js') }}"></script>
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
</head>
<body class="container">
    <div class="row">
        <h5>Click to start an ansycnhronous task with automatic feedback.</h5>
    </div>
    <div class="card-panel">
        <form method='post' id="runTaskForm" action="/runAsyncTask">
            <button style="height:50px;width:400px" type="submit" id="runTask">Run An Asynchronous Task With Automatic Feedback</button>
        </form>
    </div>
    <div class="row">
        <div id="Messages" class="red-text" style="width:800px; height:400px; overflow-y:scroll;"></div>
    </div>
    <script>
        $(document).ready(function() {
            var namespace = '/runAsyncTaskF';
            var url = 'http://' + document.domain + ':' + location.port + namespace;
            var socket = io.connect(url);
            socket.on('connect', function() {
                ////alert('socket on connect');
                socket.emit('join_room');
            });
            socket.on('msg', function(data) {
                ////alert('socket on msg ='+ data.msg);
                $("#Messages").prepend('<li>' + data.msg + '</li>');
            });
            socket.on('status', function(data) {
                ////alert('socket on status ='+ data.msg);
                if (data.msg == 'End') {
                    $("#runTask").attr("disabled", false);
                };
            });
        });
    </script>
    <script>
        $("#runTask").click(function(e) {
            $("#runTask").attr("disabled", true);
            $("*").css("cursor", "wait");
            $("#Messages").empty();

            $.ajax({
                type: "Post",
                url: '/runAsyncTaskF',
                data: $("#runTaskForm").serialize(),
                success: function(data) {
                    $("*").css("cursor", "");
                    $("#Messages").empty();
                    $("#Messages").prepend('<li>The Task ' + data.taskid + ' has been submitted. </li>');
                }
            });
            e.preventDefault();
            console.log('runAsyncTaskF complete');
        });
    </script>
</body>
</html>

app_async2.pyFlaskアプリケーションを含むと呼ばれるプログラムを作成します。

#Gevent is a coroutine based concurrency library for Python
from gevent import monkey
#For dynamic modifications of a class or module
monkey.patch_all()
from flask import render_template, jsonify, session, request
from random import randint
import uuid
import tasks
from init import app, socketio
from flask_socketio import join_room

@app.route("/",methods=['GET'])
def index():
    # create a unique session ID and store it within the Flask session
    if 'uid' not in session:
        sid = str(uuid.uuid4())
        session['uid'] = sid
        print("Session ID stored =", sid)
    return render_template('index2.html')

#Run an Asynchronous Task With Automatic Feedback
@app.route("/runAsyncTaskF",methods=['POST'])
def long_async_taskf():
    print("Running", "/runAsyncTaskF")
    # Generate a random number between MIN_WAIT_TIME and MAX_WAIT_TIME
    n = randint(app.config['MIN_WAIT_TIME'], app.config['MAX_WAIT_TIME'])

    data = {}
    data['sessionid'] = str(session['uid'])
    data['waittime']  = n
    data['namespase'] = '/runAsyncTaskF'

    task = tasks.long_async_taskf.delay(data)
    return jsonify({ 'taskid':task.id
                    ,'sessionid':data['sessionid']
                    ,'waittime':data['waittime']
                    ,'namespace':data['namespase']
                    })

@socketio.on('connect', namespace='/runAsyncTaskF')
def socket_connect():
    #Display message upon connecting to the namespace
    print('Client Connected To NameSpace /runAsyncTaskF - ',request.sid)

@socketio.on('disconnect', namespace='/runAsyncTaskF')
def socket_connect():
    # Display message upon disconnecting from the namespace
    print('Client disconnected From NameSpace /runAsyncTaskF - ',request.sid)

@socketio.on('join_room', namespace='/runAsyncTaskF')
def on_room():
    room = str(session['uid'])
    # Display message upon joining a room specific to the session previously stored.
    print(f"Socket joining room {room}")
    join_room(room)

@socketio.on_error_default
def error_handler(e):
    # Display message on error.
    print(f"socket error: {e}, {str(request.event)}")

if __name__ == "__main__":
    # Run the application with socketio integration.
    socketio.run(app,debug=True)

このプログラムには、主に2つのルートがあります。

  • "/":Webページをレンダリングします(index2.html)。
  • "/runAsyncTaskF":以下を実行する非同期タスクを呼び出します。
    • 1〜20秒の乱数を生成します。
    • long_async_taskf() プログラム内のそれぞれのタスクを呼び出しますtasks.py

このシナリオを実行するには:

  • Redisサーバーを起動します。
  • セロリワーカーを起動します。
  • 走る app_async2.py

ブラウザを開き、次のリンクにアクセスしてボタンを押すと、次のような出力が徐々に表示されます。

自動フィードバックフラスコアプリとの非同期通信同時に、コンソールに次の出力が表示されます。

コンソール出力またcelery.logs、タスクのライフサイクルについてファイルをいつでも確認できます。

シナリオ4:自動フィードバックを使用してポートでスケジュールされた非同期サービスコールを表示する

このシナリオはシナリオ3に似ています。唯一の違いは、非同期タスクを直接実行する代わりに、このタスクがクライアントによって指定された特定の期間の後に実行されるようにスケジュールされることです。
 

コーディングに進みましょう。非同期タスクを実行する前に待機する時間を秒単位で表すindex3.html新しいフィールドを使用してテンプレートを作成し"Duration"ます。

<!DOCTYPE html>
<html>
<head>
    <title>Synchronicity versus Asynchronicity</title>
    <link rel="stylesheet" href="{{url_for('static',filename='css/materialize.min.css')}}">
    <script src="{{ url_for('static',filename='js/jquery.min.js') }}"></script>
    <script src="{{ url_for('static',filename='js/socket.io.js') }}"></script>
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
</head>
<body class="container">
    <div class="row">
        <h5>Click to start a post scheduled ansycnhronous task with automatic feedback.</h5>
    </div>
    <div class="card-panel">
        <form method='post' id="runTaskForm" action="/runPSATask">
            <div>
                <input id="duration" name="duration" placeholder="Enter duration in seconds. for example: 30" type="text">
                <label for="duration">Duration</label>
            </div>
            <button style="height:50px;width:600px" type="submit" id="runTask">Run A Post Scheduled Asynchronous Task With Automatic Feedback</button>
        </form>
    </div>
    <div class="row">
        <div id="Messages" class="red-text" style="width:800px; height:400px; overflow-y:scroll;"></div>
    </div>
    <script>
        $(document).ready(function() {
            var namespace = '/runPSATask';
            var url = 'http://' + document.domain + ':' + location.port + namespace;
            var socket = io.connect(url);
            socket.on('connect', function() {
                socket.emit('join_room');
            });
            socket.on('msg', function(data) {
                $("#Messages").prepend('<li>' + data.msg + '</li>');
            });
            socket.on('status', function(data) {
                ////alert('socket on status ='+ data.msg);
                if (data.msg == 'End') {
                    $("#runTask").attr("disabled", false);
                };
            });
        });
    </script>
    <script>
        $("#runTask").click(function(e) {
            $("#runTask").attr("disabled", true);
            $("#Messages").empty();
            $.ajax({
                type: "Post",
                url: '/runPSATask',
                data: $("#runTaskForm").serialize(),
                success: function(data) {
                    $("#Messages").empty();
                    $("#Messages").prepend('<li>The Task ' + data.taskid + ' has been submitted and will execute in ' + data.duration + ' seconds. </li>');
                }
            });
            e.preventDefault();
            console.log('runPSATask complete');
        });
    </script>
</body>
</html>

次に、app_async3.pyこのシナリオのFlaskアプリは次のとおりです。

#app_async3.py
from gevent import monkey
monkey.patch_all()

from flask import render_template, jsonify, session, request
from random import randint
import uuid
import tasks
from init import app, socketio
from flask_socketio import join_room

@app.route("/",methods=['GET'])
def index():
    # create a unique session ID
    if 'uid' not in session:
        sid = str(uuid.uuid4())
        session['uid'] = sid
        print("Session ID stored =", sid)
    return render_template('index3.html')

#Run a Post Scheduled Asynchronous Task With Automatic Feedback
@app.route("/runPSATask",methods=['POST'])
def long_async_sch_task():
        print("Running", "/runPSATask")
        # Generate a random number between MIN_WAIT_TIME and MAX_WAIT_TIME
        n = randint(app.config['MIN_WAIT_TIME'], app.config['MAX_WAIT_TIME'])
        data = {}
        data['sessionid'] = str(session['uid'])
        data['waittime']  = n
        data['namespase'] = '/runPSATask'
        data['duration']  = int(request.form['duration'])
        #Countdown represents the duration to wait in seconds before running the task
        task = tasks.long_async_sch_task.apply_async(args=[data],countdown=data['duration'])
        return jsonify({ 'taskid':task.id
                        ,'sessionid':data['sessionid']
                        ,'waittime': data['waittime']
                        ,'namespace':data['namespase']
                        ,'duration':data['duration']
                        })


@socketio.on('connect', namespace='/runPSATask')
def socket_connect():
    print('Client Connected To NameSpace /runPSATask - ',request.sid)

@socketio.on('disconnect', namespace='/runPSATask')
def socket_connect():
    print('Client disconnected From NameSpace /runPSATask - ',request.sid)

@socketio.on('join_room', namespace='/runPSATask')
def on_room():
    room = str(session['uid'])
    print(f"Socket joining room {room}")
    join_room(room)

@socketio.on_error_default
def error_handler(e):
    print(f"socket error: {e}, {str(request.event)}")

if __name__ == "__main__":
    socketio.run(app,debug=True)

今回long_async_sch_task()からタスクメソッドを使用していることに注意してくださいtasks.py

app_async3.py以前と同じように実行し、ブラウザを開きます。

シナリオ4アプリ期間(つまり10)を入力し、ボタンを押して、スケジュール後の非同期タスクを作成します。作成されると、タスクの詳細を示すメッセージが[メッセージ]ボックスに表示されます。

期間フィールドで指定した時間待つ必要があります。タスクが実行されていることがわかります。

実行中のスケジュールされたタスクを投稿するまた、celery.logsログファイルに含まれているセロリワーカーのログを復元すると、タスクのライフサイクルに気付くでしょう。

シナリオ4のログファイル付録:セロリの監視に花を使用する

セロリタスクをより適切に監視するために、セロリ クラスターを監視および管理するためのWebベースのツールであるFlowerをインストールできます。

注意:フラワーライブラリはの一部でしたrequirements.txt。 

花を使用してセロリのタスクを表示するには、次の手順に従ってください。

  • 以前と同じようにRedisサーバーを起動します。
  • 以前と同じようにCeleryワーカーを起動します。
  • Windowsでは、コマンドを使用してflowerを開始します。
$ async-venv\Scripts\flower.exe worker -A tasks --port=5555

Linux / MacOSの場合:

$ async-venv/bin/flower worker -A tasks --port=5555

コンソールに次の情報が表示されます。

花が始まりましたアプリに戻ってタスクを実行し、ブラウザを開いてhttp://localhost:5555[タスク]タブに移動します。

花のホームページ

タスクが完了すると、フラワーダッシュボードに次のように表示されます。

フラワーダッシュボードのセロリで達成されたタスク結論

この記事が、Celeryの助けを借りて同期および非同期リクエストの概念的な基礎を得るのに役立つことを願っています。同期要求は遅くなる可能性があり、非同期要求は迅速に実行されますが、あらゆるシナリオに適切な方法を認識することが重要です。時には、彼らは一緒に働くことさえあります。

リンク: https://www.thepythoncode.com/article/async-tasks-with-celery-redis-and-flask-in-python

#python 
 

 

PythonでのCeleryを使用した非同期タスク