Extended Date [Windows, Linux, MacOS]
Extended Date [Windows, Linux, MacOS]
Unlike the very nice ASM code of wilbert (Thread), no complicated ASM code was used, so the codes should be easy to understand, changeable and extensible.
https://github.com/SicroAtGit/PureBasic ... Mac%5D.pbi
The code already exists for a while in the German forum.
The MacOS support I have now restored.
The following codes use only the PB-Date library and extend the date range anyway:
https://github.com/SicroAtGit/PureBasic ... dTimeA.pbi
https://github.com/SicroAtGit/PureBasic ... /DateX.pbi
It would be nice if you would test the codes with different time zones.
Let's extend the existing codes to create a date module that works fully functional and error-free under all OS, instead of writing a new code again and again.
https://github.com/SicroAtGit/PureBasic ... Mac%5D.pbi
The code already exists for a while in the German forum.
The MacOS support I have now restored.
The following codes use only the PB-Date library and extend the date range anyway:
https://github.com/SicroAtGit/PureBasic ... dTimeA.pbi
https://github.com/SicroAtGit/PureBasic ... /DateX.pbi
It would be nice if you would test the codes with different time zones.
Let's extend the existing codes to create a date module that works fully functional and error-free under all OS, instead of writing a new code again and again.
Why OpenSource should have a license :: PB-CodeArchiv-Rebirth :: Pleasant-Dark (syntax color scheme) :: RegEx-Engine (compiles RegExes to NFA/DFA)
Manjaro Xfce x64 (Main system) :: Windows 10 Home (VirtualBox) :: Newest PureBasic version
Re: Extended Date [Windows, Linux, MacOS]
To me dates prior to 1970 are just as important as beyond 2038.Sicro wrote:It would be nice if you would test the codes with different time zones.
I think all OS should support at least 01.01.1601 00:00:00 as the earliest date.
Therefore I recommend to use CFCalendarDecomposeAbsoluteTime for MacOS.
I would also suggest a procedure that takes two date values for input and outputs how many years, months, days etc. the two dates are apart.
For a module where multiple people contribute, I would also appreciate it if it can be commented in English. I understand some of your comments but not all of it.
MacOS by the way internally uses the calendar api from the open source library "International Components for Unicode".Sicro wrote:Let's extend the existing codes to create a date module that works fully functional and error-free under all OS, instead of writing a new code again and again.
http://icu-project.org/apiref/icu4c/ucal_8h.html
Windows (x64)
Raspberry Pi OS (Arm64)
Raspberry Pi OS (Arm64)
Re: Extended Date [Windows, Linux, MacOS]
Here's an example of how your procedures can look on MacOS with support for a bigger date range and also working on x86.
It contains an init procedure to initialize a few global values that would be private to the module.
The same but now using the ICU library (the library could be compiled for Windows and Linux as well).
It contains an init procedure to initialize a few global values that would be private to the module.
Code: Select all
ImportC ""
CFCalendarAddComponents(calendar, *at, options, componentDesc.p-ascii, value)
CFCalendarComposeAbsoluteTime(calendar, *at, componentDesc.p-ascii, year, month, day, hour, minute, second)
CFCalendarCreateWithIdentifier(allocator, identifier)
CFCalendarDecomposeAbsoluteTime(calendar, at.d, componentDesc.p-ascii, *component)
CFCalendarSetTimeZone(calendar, tz)
CFTimeZoneCopyDefault()
CFTimeZoneCreateWithTimeIntervalFromGMT(allocator, ti.d)
CFTimeZoneGetSecondsFromGMT.d(tz, at.d)
EndImport
Global.i GregorianGMT, TimeZone
Procedure Date64Init(); Init global variables GregorianGMT and TimeZone
Protected *kCFGregorianCalendar.Integer = dlsym_(#RTLD_DEFAULT, "kCFGregorianCalendar")
TimeZone = CFTimeZoneCreateWithTimeIntervalFromGMT(0, 0)
GregorianGMT = CFCalendarCreateWithIdentifier(0, *kCFGregorianCalendar\i)
CFCalendarSetTimeZone(GregorianGMT, TimeZone)
CFRelease_(TimeZone)
TimeZone = CFTimeZoneCopyDefault()
EndProcedure
Date64Init()
Procedure.q Date64(Year.i=-1, Month.i=1, Day.i=1, Hour.i=0, Minute.i=0, Second.i=0)
Protected at.d
If Year > -1
CFCalendarComposeAbsoluteTime(GregorianGMT, @at, "yMdHms", Year, Month, Day, Hour, Minute, Second)
Else
at = CFAbsoluteTimeGetCurrent_()
at + CFTimeZoneGetSecondsFromGMT(TimeZone, at)
EndIf
ProcedureReturn at + 978307200
EndProcedure
Macro Mac_ReturnDatePart(Type)
Protected.i DatePart
CFCalendarDecomposeAbsoluteTime(GregorianGMT, Date - 978307200, Type, @DatePart)
CompilerIf Type = "E"
ProcedureReturn DatePart - 1
CompilerElse
ProcedureReturn DatePart
CompilerEndIf
EndMacro
Procedure.i Year64(Date.q)
Mac_ReturnDatePart("y")
EndProcedure
Procedure.i Month64(Date.q)
Mac_ReturnDatePart("M")
EndProcedure
Procedure.i Day64(Date.q)
Mac_ReturnDatePart("d")
EndProcedure
Procedure.i Hour64(Date.q)
Mac_ReturnDatePart("H")
EndProcedure
Procedure.i Minute64(Date.q)
Mac_ReturnDatePart("m")
EndProcedure
Procedure.i Second64(Date.q)
Mac_ReturnDatePart("s")
EndProcedure
Procedure.i DayOfWeek64(Date.q)
Mac_ReturnDatePart("E")
EndProcedure
Procedure.i DayOfYear64(Date.q)
Mac_ReturnDatePart("D")
EndProcedure
Procedure.q AddDate64(Date.q, Type.i, Value.i)
Protected at.d = Date - 978307200
Select Type
Case #PB_Date_Year: CFCalendarAddComponents(GregorianGMT, @at, 0, "y", Value)
Case #PB_Date_Month: CFCalendarAddComponents(GregorianGMT, @at, 0, "M", Value)
Case #PB_Date_Week: CFCalendarAddComponents(GregorianGMT, @at, 0, "d", Value * 7)
Case #PB_Date_Day: CFCalendarAddComponents(GregorianGMT, @at, 0, "d", Value)
Case #PB_Date_Hour: CFCalendarAddComponents(GregorianGMT, @at, 0, "H", Value)
Case #PB_Date_Minute: CFCalendarAddComponents(GregorianGMT, @at, 0, "m", Value)
Case #PB_Date_Second: CFCalendarAddComponents(GregorianGMT, @at, 0, "s", Value)
EndSelect
ProcedureReturn at + 978307200
EndProcedure
; Test
Date.q = Date64(1510,2)
Date = AddDate64(Date, #PB_Date_Month, -1)
Debug "Year: " + Str(Year64(Date))
Debug "Month: " + Str(Month64(Date))
Debug "Day: " + Str(Day64(Date))
Debug "Hour: " + Str(Hour64(Date))
Debug "Minute: " + Str(Minute64(Date))
Debug "Second: " + Str(Second64(Date))
Debug "Day of year: " + Str(DayOfYear64(Date))
Debug "Day of week: " + Str(DayOfWeek64(Date))
Code: Select all
#UCAL_GREGORIAN = 1
#UCAL_YEAR = 1
#UCAL_MONTH = 2
#UCAL_WEEK_OF_YEAR = 3
#UCAL_DAY_OF_MONTH = 5
#UCAL_DAY_OF_YEAR = 6
#UCAL_DAY_OF_WEEK = 7
#UCAL_HOUR_OF_DAY = 11
#UCAL_MINUTE = 12
#UCAL_SECOND = 13
#UCAL_ZONE_OFFSET = 15
#UCAL_DST_OFFSET = 16
#UCAL_EXTENDED_YEAR = 19
ImportC "-licucore"
ucal_add(*cal, field, amount.l, *status.Long)
ucal_clear(*cal)
ucal_clone(*cal, *status.Long)
ucal_close(*cal)
ucal_get.l(*cal, field, *status.Long)
ucal_getMillis.d(*cal, *status.Long)
ucal_getNow.d()
ucal_open(*zoneID, len.l, *locale, type, *status.Long)
ucal_setDateTime(*cal, year.l, month.l, date.l, hour.l, minute.l, second.l, *status.Long)
ucal_setMillis(*cal, dateTime.d, *status.Long)
EndImport
Global *cal_GMT, *cal_local
Procedure Date64Init()
Protected status.l, GMT.q = $47004D0054; 'GMT'
*cal_GMT = ucal_open(@GMT, -1, #Null, #UCAL_GREGORIAN, @status); Gregorian GMT
*cal_local = ucal_open(#Null, 0, #Null, #UCAL_GREGORIAN, @status); Gregorian local
ucal_clear(*cal_GMT)
ucal_clear(*cal_local)
EndProcedure
Date64Init()
Procedure.q Date64(Year.i=$7fffffff, Month.i=1, Day.i=1, Hour.i=0, Minute.i=0, Second.i=0)
Protected *cal, status.l, at.d
If Year <> $7fffffff
*cal = ucal_clone(*cal_GMT, @status)
ucal_setDateTime(*cal, Year, Month - 1, Day, Hour, Minute, Second, @status)
at = ucal_getMillis(*cal, @status)
Else
*cal = ucal_clone(*cal_local, @status)
at = ucal_getNow()
ucal_setMillis(*cal, at, @status)
at + ucal_get(*cal, #UCAL_ZONE_OFFSET, @status)
at + ucal_get(*cal, #UCAL_DST_OFFSET, @status)
EndIf
ucal_close(*cal)
ProcedureReturn at * 1e-3
EndProcedure
Macro Mac_ReturnDatePart(Type)
Protected *cal, status.l, datepart.i
*cal = ucal_clone(*cal_GMT, @status)
ucal_setMillis(*cal, Date * 1e3, @status)
CompilerIf Type = #UCAL_MONTH
datepart = ucal_get(*cal, Type, @status) + 1
CompilerElseIf Type = #UCAL_DAY_OF_WEEK
datepart = ucal_get(*cal, Type, @status) - 1
CompilerElse
datepart = ucal_get(*cal, Type, @status)
CompilerEndIf
ucal_close(*cal)
ProcedureReturn datepart
EndMacro
Procedure.i Year64(Date.q)
Mac_ReturnDatePart(#UCAL_EXTENDED_YEAR)
EndProcedure
Procedure.i Month64(Date.q)
Mac_ReturnDatePart(#UCAL_MONTH)
EndProcedure
Procedure.i Day64(Date.q)
Mac_ReturnDatePart(#UCAL_DAY_OF_MONTH)
EndProcedure
Procedure.i Hour64(Date.q)
Mac_ReturnDatePart(#UCAL_HOUR_OF_DAY)
EndProcedure
Procedure.i Minute64(Date.q)
Mac_ReturnDatePart(#UCAL_MINUTE)
EndProcedure
Procedure.i Second64(Date.q)
Mac_ReturnDatePart(#UCAL_SECOND)
EndProcedure
Procedure.i DayOfWeek64(Date.q)
Mac_ReturnDatePart(#UCAL_DAY_OF_WEEK)
EndProcedure
Procedure.i DayOfYear64(Date.q)
Mac_ReturnDatePart(#UCAL_DAY_OF_YEAR)
EndProcedure
Procedure.q AddDate64(Date.q, Type.i, Value.i)
Protected *cal, status.l, at.d
*cal = ucal_clone(*cal_GMT, @status)
ucal_setMillis(*cal, Date * 1e3, @status)
Select Type
Case #PB_Date_Year: ucal_add(*cal, #UCAL_YEAR, Value, @status)
Case #PB_Date_Month: ucal_add(*cal, #UCAL_MONTH, Value, @status)
Case #PB_Date_Week: ucal_add(*cal, #UCAL_DAY_OF_MONTH, Value * 7, @status)
Case #PB_Date_Day: ucal_add(*cal, #UCAL_DAY_OF_MONTH, Value, @status)
Case #PB_Date_Hour: ucal_add(*cal, #UCAL_HOUR_OF_DAY, Value, @status)
Case #PB_Date_Minute: ucal_add(*cal, #UCAL_MINUTE, Value, @status)
Case #PB_Date_Second: ucal_add(*cal, #UCAL_SECOND, Value, @status)
EndSelect
at = ucal_getMillis(*cal, @status)
ucal_close(*cal)
ProcedureReturn at * 1e-3
EndProcedure
; Test
Date.q = Date64(1510,2)
Date = AddDate64(Date, #PB_Date_Month, -1)
Debug "Year: " + Str(Year64(Date))
Debug "Month: " + Str(Month64(Date))
Debug "Day: " + Str(Day64(Date))
Debug "Hour: " + Str(Hour64(Date))
Debug "Minute: " + Str(Minute64(Date))
Debug "Second: " + Str(Second64(Date))
Debug "Day of year: " + Str(DayOfYear64(Date))
Debug "Day of week: " + Str(DayOfWeek64(Date))
Last edited by wilbert on Sat Jul 29, 2017 8:46 pm, edited 2 times in total.
Windows (x64)
Raspberry Pi OS (Arm64)
Raspberry Pi OS (Arm64)
Re: Extended Date [Windows, Linux, MacOS]
Very many thanks, wilbert! Very nice!
The "ICU" library looks very good, but it has too many functions that has nothing to do with date functions. Thus it is to overload for our purposes.
What are the date limits for "CFCalendarDecomposeAbsoluteTime"?
The current version of Date64 is temporarily available here:
https://github.com/SicroAtGit/PureBasic ... Mac%5D.pbi
Donewilbert wrote:Therefore I recommend to use CFCalendarDecomposeAbsoluteTime for MacOS.
The "ICU" library looks very good, but it has too many functions that has nothing to do with date functions. Thus it is to overload for our purposes.
wilbert wrote:I would also suggest a procedure that takes two date values for input and outputs how many years, months, days etc. the two dates are apart.
Code: Select all
a = Date64::Date64(2017, 1, 1, 0, 0, 0)
b = Date64::Date64(2017, 2, 1, 0, 0, 0)
Debug "Difference:"
Debug ""
x = b - a
Debug "In seconds: " + Str(x)
Debug "In minutes: " + Str(x / 60)
Debug "In hours: " + Str(x / 60 / 60)
Debug "In days: " + Str(x / 60 / 60 / 24)
Debug "In weeks: " + Str(x / 60 / 60 / 24 / 7)
Donewilbert wrote:For a module where multiple people contribute, I would also appreciate it if it can be commented in English. I understand some of your comments but not all of it.
What are the date limits for "CFCalendarDecomposeAbsoluteTime"?
The current version of Date64 is temporarily available here:
https://github.com/SicroAtGit/PureBasic ... Mac%5D.pbi
Why OpenSource should have a license :: PB-CodeArchiv-Rebirth :: Pleasant-Dark (syntax color scheme) :: RegEx-Engine (compiles RegExes to NFA/DFA)
Manjaro Xfce x64 (Main system) :: Windows 10 Home (VirtualBox) :: Newest PureBasic version
Re: Extended Date [Windows, Linux, MacOS]
You are probably right. For MacOS it won't be a problem since the dynamic library is already included in the OS.Sicro wrote:The "ICU" library looks very good, but it has too many functions that has nothing to do with date functions. Thus it is to overload for our purposes.
I believe in it's current form from January 1 of the year 1 AD until about 5.8 million years AD.Sicro wrote:What are the date limits for "CFCalendarDecomposeAbsoluteTime"?
The ICU version from about 5.8 million years BC until about 5.8 million years AD.
The question of course is how useful it is to have years with over 4 digits because it would be hard to format them in a string.
Additional benefits of the ICU version are that on MacOS it generates smaller executables and the code is threadsafe.
The CFCalendar based code could also be made threadsafe by creating and releasing a calendar object inside each procedure instead of a global object but that would make it much slower.
Windows (x64)
Raspberry Pi OS (Arm64)
Raspberry Pi OS (Arm64)
Re: Extended Date [Windows, Linux, MacOS]
I have now read the documentation about the date functions of the library "icu" a bit.
However, this does not work under Linux:Presumably it has a different name.
If it would also work under Linux, only the implementation for Windows would be missing. For the Windows support, we would have to compile the library "icu" to a DLL, which is reduced in the functional scope and contains at best only the date functions.
I find a strong disadvantage with the library "icu" that it does not take the time zone information from the operating system, but has its own sources for this information:
http://userguide.icu-project.org/datetime/timezone
"Updating the Time Zone Data"
The bibliothek must therefore always be renewed when the time zone information changes. For the API date functions of the operating system, this information is automatically updated via the system update.
In the thread of the German Forum, the forum member "Lord" has pointed out to me that there are different introduction times of the gegorian calendar in some countries. In addition, there are some time jumps during the calendar change.
Many date functions (for example, those of sqlite or the operating systems) do not take the differences and time jumps into account.
I have created a correction function for these time jumps for our module:
http://www.purebasic.fr/german/viewtopi ... 10#p341910
In the package manager of my Linux operating system, the library "icu" is also displayed as already installed. I do not know whether the library was installed from the very beginning or was installed later by installing a program.wilbert wrote:You are probably right. For MacOS it won't be a problem since the dynamic library is already included in the OS.Sicro wrote:The "ICU" library looks very good, but it has too many functions that has nothing to do with date functions. Thus it is to overload for our purposes.
However, this does not work under Linux:
Code: Select all
ImportC "-licucore"
If it would also work under Linux, only the implementation for Windows would be missing. For the Windows support, we would have to compile the library "icu" to a DLL, which is reduced in the functional scope and contains at best only the date functions.
I find a strong disadvantage with the library "icu" that it does not take the time zone information from the operating system, but has its own sources for this information:
http://userguide.icu-project.org/datetime/timezone
"Updating the Time Zone Data"
The bibliothek must therefore always be renewed when the time zone information changes. For the API date functions of the operating system, this information is automatically updated via the system update.
wilbert wrote:The ICU version from about 5.8 million years BC until about 5.8 million years AD.
Source: http://userguide.icu-project.org/dateti ... ltimescale29000BC..29000AD
I find it very important that the date range supported by our date module is the same under each operating system.wilbert wrote:The question of course is how useful it is to have years with over 4 digits because it would be hard to format them in a string.
Ok, this is now an argument that puts the library "icu" back in the forefront. The thread-safe use I find also very important.wilbert wrote:Additional benefits of the ICU version are that on MacOS it generates smaller executables and the code is threadsafe.
The CFCalendar based code could also be made threadsafe by creating and releasing a calendar object inside each procedure instead of a global object but that would make it much slower.
In the thread of the German Forum, the forum member "Lord" has pointed out to me that there are different introduction times of the gegorian calendar in some countries. In addition, there are some time jumps during the calendar change.
Many date functions (for example, those of sqlite or the operating systems) do not take the differences and time jumps into account.
Source: http://userguide.icu-project.org/datetime/calendarGregorian Calendar
...
Historically, most western countries used the Julian calendar until the 16th to 20th century, depending on the country. They then switched to the Gregorian calendar. The GregorianCalendar class mirrors this behavior by defining a cut-over date. Before this date, the Julian calendar algorithms are used. After it, the Gregorian calendar algorithms are used. By default, the cut-over date is set to October 4, 1582 C.E., which reflects the time when countries first began adopting the Gregorian calendar. The GregorianCalendar class does not attempt historical accuracy beyond this behavior, and does not vary its cut-over date by locale. However, users can modify the cut-over date by using the setGregorianChange() method.
I have created a correction function for these time jumps for our module:
http://www.purebasic.fr/german/viewtopi ... 10#p341910
Why OpenSource should have a license :: PB-CodeArchiv-Rebirth :: Pleasant-Dark (syntax color scheme) :: RegEx-Engine (compiles RegExes to NFA/DFA)
Manjaro Xfce x64 (Main system) :: Windows 10 Home (VirtualBox) :: Newest PureBasic version
Re: Extended Date [Windows, Linux, MacOS]
I found some precompiled dlls that might be useful to test with but the function names all have _58 added to them as far as I can tell.Sicro wrote:If it would also work under Linux, only the implementation for Windows would be missing. For the Windows support, we would have to compile the library "icu" to a DLL, which is reduced in the functional scope and contains at best only the date functions.
https://www.npcglib.org/~stathis/downlo ... -vs2013.7z
You need to look at the ICU4C UDate typeSicro wrote:wilbert wrote:The ICU version from about 5.8 million years BC until about 5.8 million years AD.Source: http://userguide.icu-project.org/dateti ... ltimescale29000BC..29000AD
The year 1582 indeed seems to have a different length.Sicro wrote:In the thread of the German Forum, the forum member "Lord" has pointed out to me that there are different introduction times of the gegorian calendar in some countries. In addition, there are some time jumps during the calendar change.
Windows (x64)
Raspberry Pi OS (Arm64)
Raspberry Pi OS (Arm64)
Re: Extended Date [Windows, Linux, MacOS]
Inspired by this post from Mesa http://www.purebasic.fr/english/viewtop ... 12&t=49665 I came up with this
It's Julian/Gregorian hybrid with a fixed cutover date of Oct 4/15, 1582.
It should be accurate up to a few million years.
It's fast, cross platform, no ASM and no API.
Code: Select all
Procedure.q Date64(Year.i=$7fffffff, Month.i=1, Day.i=1, Hour.i=0, Minute.i=0, Second.i=0)
If Year = $7fffffff
ProcedureReturn Date()
Else
While Month<3 : Year-1 : Month+12 : Wend
While Month>14 : Year+1 : Month-12 : Wend
Day+(Year*365+Year>>2)+(((Month+1)*7834)>>8)-719593
If Day>-141418 : Year/100 : Day-Year+(Year>>2)+2 : EndIf
ProcedureReturn Day*86400+Hour*3600+Minute*60+Second
EndIf
EndProcedure
It should be accurate up to a few million years.
It's fast, cross platform, no ASM and no API.
Last edited by wilbert on Thu Aug 10, 2017 5:40 pm, edited 1 time in total.
Windows (x64)
Raspberry Pi OS (Arm64)
Raspberry Pi OS (Arm64)
Re: Extended Date [Windows, Linux, MacOS]
That is not a good idea. The transition from Julian to Gregorian is depending on the location.wilbert wrote:...It's Julian/Gregorian hybrid with a fixed cutover date of Oct 4/15, 1582.Code: Select all
...
It should be accurate up to a few million years.
It's fast, cross platform, no ASM and no API.
In parts of northern europe the cutover date is Feb 19/28 1700.
In Greece in the year 1923, in China in 1949 ....
Re: Extended Date [Windows, Linux, MacOS]
Fortunately we all are entitled to our own opinions.Lord wrote:That is not a good idea. The transition from Julian to Gregorian is depending on the location.
In parts of northern europe the cutover date is Feb 19/28 1700.
In Greece in the year 1923, in China in 1949 ....
To me a transition depending on location seems like a bad idea.
If I store a date inside a program that something happened here on for example July 2nd, 1901 and someone in Greece gets presented a different date, things get very confusing. To me consistency is the most important thing.
I've seen the link Sicro quoted to the German forum with a function handling local cutover dates but if I'm not mistaken, such a table is only useful if you are programming the entire date system yourself.
If you combine it for example with the internal date system of Linux, you can skip a few days based on location but the leap days before that date are still wrong so the system still doesn't present the right local dates.
An alternative could be to use the ISO 8601 proleptic Gregorian calendar system which makes things a lot easier.
Windows (x64)
Raspberry Pi OS (Arm64)
Raspberry Pi OS (Arm64)
Re: Extended Date [Windows, Linux, MacOS]
That's true.wilbert wrote:Lord wrote:...
Fortunately we all are entitled to our own opinions.
...
I made my statement and leave you your opinion.
Re: Extended Date [Windows, Linux, MacOS]
Well, you did get me thinking and reading some moreLord wrote:That's true.
I made my statement and leave you your opinion.
From what I understand, PHP, MySQL, JavaScript, Python all use a proleptic Gregorian calendar.
It would make sense to use the same.
Windows (x64)
Raspberry Pi OS (Arm64)
Raspberry Pi OS (Arm64)
Re: Extended Date [Windows, Linux, MacOS]
So, if all are doing the same error, it is wise to make the same?wilbert wrote:...
From what I understand, PHP, MySQL, JavaScript, Python all use a proleptic Gregorian calendar.
It would make sense to use the same.
Why not doing it better and avoid possible problems?
But, as I said, it's just my opinion.
Re: Extended Date [Windows, Linux, MacOS]
There are a few other projects that I want to finish first. Before I can deal with this issue again.
But I think now and then about how best to handle the time calculations.
https://www.youtube.com/watch?v=-5wpm-gesOY
It is very complex
But I think now and then about how best to handle the time calculations.
https://www.youtube.com/watch?v=-5wpm-gesOY
It is very complex
Why OpenSource should have a license :: PB-CodeArchiv-Rebirth :: Pleasant-Dark (syntax color scheme) :: RegEx-Engine (compiles RegExes to NFA/DFA)
Manjaro Xfce x64 (Main system) :: Windows 10 Home (VirtualBox) :: Newest PureBasic version