How to parse string to AnnualDate in NodaTime - nodatime

I cannot find anywhere in the documentation how to parse the annual date string, e.g. 09-01 to AnnualDate.
I'm saving AnnualDate as a string in the database and I need to convert it to AnnualDate when implementing custom conversion in EF.
The only constructor AnnualDate has is AnnualDate(int, int) and I cannot find the parse method anywhere.

It's the same as with all other NodaTime types - you use a pattern, in this case NodaTime.Text.AnnualDatePattern.
So:
var result = AnnualDatePattern.Iso.Parse(text);
if (result.Success)
{
var annualDate = result.Value;
...
}
else
{
// Handle failure
}

Related

Why are Next.js' req.query object's values of type string | string[]?

Next.js' API Routes receive a req object - it's an extension of http.IncomingMessage with additional middlewares such as req.query. The typing of req.query, found in their utils.ts, is:
query: {
[key: string]: string | string[]
}
Why is it possible to receive an array of strings from the query?
I'm trying to perform string methods on my query values but run into TS errors -_-
someString.split() // => Property 'split' does not exist on type 'string | string[]'.
the query object is of type string | string[] because of catch all routes
https://nextjs.org/docs/routing/dynamic-routes
if you had a file that was named [id].js and used the url pages/123, router.query would return a string 123, but if the file was named [...id].js and used the url pages/123 it would be a catch all route and would return an array ["123"], if the url were pages/123/456 it would return ["123", "456"]
I think we can use this, if we don't work with more than one param with the same name:
const id = req.query.id as string
You can convert 'string | string[]' to 'string' by joining them like this:
let { param } = req.query.param;
if (Array.isArray(param)) {
param = param.join('');
}
Just like Bruno mentioned. If we know that our page is [id].tsx, I think it's safe to use type assertion.
const id = req.query.id as string
I'm not really sure if explicit type narrowing is needed in this case as routing to this page is ensured to contain id as string by nextjs. Is there really a chance that this type assertion can go wrong?
Similar to the solutions suggested above but with support for multiple params
const { param1, param2 } = req.query as { param1: string; param2: string };

How to write a string regix in typescript take 'href' value?

I need to take 'href'(tag link location value) value from following pattern html text. need some expert help to do it using typescript
String Text one
"<html><body>docker_command.txt </body></html>"
String Text Two
"<html><body>https://www.facebook.com/ </body></html>"
Something like this?
const a = '"<html><body>docker_command.txt </body></html>"';
const b = '"<html><body>https://www.facebook.com/ </body></html>"';
function getHref(html: string): string|null {
if (!html) {
return null;
}
return html.match(/ href=("|')([^'"]*?)('|")/i)[2];
}
console.log(getHref(a));
console.log(getHref(b));

Type Assertions not Working when Reading Firestore Data

I am trying to read a complex document from Firebase in order to do some calculations and then execute a Cloud Function.
Unfortunately, I am unable to read the data in the data types that I would like.
Here is an example:
interface CourseEvent {
coucourseGroupType: string;
date: FirebaseFirestore.Timestamp;
courseGroupTypeFirebaseId: string;
firebaseId: string;
maxParticipants: number;
participants: Participant[];
start: FirebaseFirestore.Timestamp;
waitingList: Participant[];
weekNumber: string;
}
This is where I am using the Cloud Function
import * as functions from "firebase-functions";
import { firestore, Timestamp, FieldValue } from "./setup";
export const registerCustomerFromWaitingList = functions.firestore
.document("CourseEvents/{courseEvent}")
.onUpdate(async (change, context) => {
const currentCourseEvent = change.after.data() as CourseEvent;
const currentMaxParticipants = currentCourseEvent.maxParticipants;
if (typeof currentMaxParticipants === "number") {
console.log(`currentMaxParticipants type is number`);
} else if (typeof currentMaxParticipants === "string") {
console.log(`currentMaxParticipants type is string`);
} else {
console.log(`currentMaxParticipants type is NOT number or string`);
}
}
The console always prints that the currentMaxParticipants is a string. I have a similar problem also with another interface.
I also have experimented with such code
const nu = change.after.data().maxParticipants as number;
But in the end, I am still getting a string.
Any tips?
I found out why I would get always a string for the currentMaxParticipants variable.
In Firestore I did save it as a string. I thought that by using type assertions I would also convert the value. In the end, I did change the value within Firestore to a number and now it is working.
I just read this here:
Essential TypeScript: From Beginner to Pro
CAUTION No type conversion is performed by a type assertion, which only tells the compiler what type it should apply to a value for the
purposes of type checking.

I am trying to get readable date from firestore

I am trying to get readable date from Timestamp data type in my firestore database.
for (var ticketDoc of ticketsSnapshot.docs) {
var timeStamp = await ticketDoc.data().TimePreferred;
console.log(timeStamp.toDate());
var time = new Date(timeStamp).toDate();
ticketDoc.data().TimePreferred = time;
tickets.push(ticketDoc.data());
}
I read the question about a similar problem at :
How do I convert a Firestore date/Timestamp to a JS Date()?
so, i tried to do same and i expect the output of readable date, although it gives me the correct result in
console.log(timeStamp.toDate());
but also it gives me an error. Console output as follow :-
2019-04-10T06:30:00.000Z
TypeError: (intermediate value).toDate is not a function
Not : I am trying to get readable date in postman
I don't know why this timestamp object doesn't have the .toDate() extension, but if it has the 'seconds' and 'nanoseconds' properties, you can turn it to a JS Data with
Date(data.seconds)
Change the following line:
var time = new Date(timeStamp).toDate();
into this:
var time = new Date(timeStamp).toDateString();
From the docs:
A string representing the date portion of the given Date object in human readable form in American English.
You can try in the following way
{{ formatDate(new Date(data.seconds*1000)) }}
You can use the format date function to display in desired format.
import moment from "moment";
format_date(value) {
if (value) {
return moment(String(value)).format("DD/MM/YYYY");
}
},
Have you tried changing this to
var time = (new Date(timeStamp)).toDateString();
If the TimePreferred field in your document is a Timestamp, you can get a valid Date object from it by simply calling toDate() on it.
So:
for (var ticketDoc of ticketsSnapshot.docs) {
var date = ticketDoc.data().TimePreferred.toDate();
}
None of these calls are asynchronous or returning a promise, so you don't need await.
From reasons that I don't know, it doesn't work at times, so a safer option would be to use the seconds and nanoseconds attributes found in the timestamp to convert it to date as follows:
const date = new Date(timestamp.seconds*1000 + timestamp.nanoseconds/100000)
// construct the date from the absolute time in milliseconds
Note:
1 second = 1000 ms
1 nanosecond = 10^-6 ms
You have to first make sure that the timestamp object is truly of type Timestamp.
to do this, after you get the Timestamp from Firebase, create the Timestamp object:
const timestampObject: Timestamp = !!timeStamp
? new Timestamp(timeStamp.seconds, timeStamp.nanoseconds)
: null;
For Angular
import { Location, DatePipe } from '#angular/common';
constructor(
public datepipe: DatePipe
) { }
const dayAsTimestamp = your_Timestamp_value;
const dayAsDate = new Date(dayAsTimestamp.seconds * 1000);
const dayAsString = this.datepipe.transform(dayAsDate, 'dd-MMM-yyyy');

Swift UTF16 Substring

I'm receiving a string from the server in the following format:
118|...message...215|...message2...
Basically, it's the message length followed by a pipe and the message itself, repeated for multiple messages. The message is encoded UTF16.
I'm looking for a way to parse this in Swift. I know I could cast this as NSString and use standard indexes/ranges on that because UTF16 is what NSString uses, but I'm wondering what is the Swift way to handle this? I can't seem to find a way to pull a substring out of a String based on a UTF16 encoding.
Update
I'm not trying to initialize a String with raw UTF16 Data (there's plenty of ways to do that). I already have the string, so I'm trying to take a String in the above format and parse it. The issue I have is that the message length given to me by the server is based on UTF16. I can't simply extract the length and call String.advance(messageLength) on the Index because the length I've been given doesn't match the grapheme clusters that Swift advances on. My issue is that I can't extract from the string the message in Swift. I have to instead cast it over to NSString and then use "normal" NSRange on it. My question is how do I pull the substring out by extracting a range based on my search for the first pipe, and then use the length provided by the parser in UTF16.
This is all extremely simple to do with NSString. Not sure how it can be done in pure Swift (or if it can be done).
Here is my take on parsing the messages out of the string. I had to change your lengths to work with the string.
let message = "13|...message...14|...message2..."
let utf16 = message.utf16
var startingIndex = message.utf16.startIndex
var travellingIndex = message.utf16.startIndex
var messages = [String]()
var messageLength: Int
while travellingIndex != message.utf16.endIndex {
// Start walking through each character
if let char = String(utf16[travellingIndex..<travellingIndex.successor()]) {
// When we find the pipe symbol try to parse out the message length
if char == "|" {
if let stringNumber = Int(String(utf16[startingIndex..<travellingIndex])) {
messageLength = stringNumber
// We found the lenght, now skip the pipe character
startingIndex = travellingIndex.successor()
// move the travelingIndex to the end of the message
travellingIndex = travellingIndex.advancedBy(messageLength)
// get the message and put it into an array
if let message = String(utf16[startingIndex...travellingIndex]) {
messages.append(message)
startingIndex = travellingIndex.successor()
}
}
}
}
travellingIndex = travellingIndex.successor()
}
print(messages)
The output I get at the end is:
["...message...", "...message2..."]
The Foundation framework extends String to be initialisable from data:
import Foundation
let string = String(data: data, encoding: NSUTF16StringEncoding)
Getting rid of Foundation is not possible unless you implement the decoding yourself. Note that with Swift going open-source, Foundation is getting reimplemented without Objective-C dependency here.
EDIT: Thanks, Martin R, the link you provided is indeed working in pure Swift :D
EDIT:
There is the utf16 property of a String whose count property is the length in UTF16. Here is a simple parser for your purpose, efficiency isn't great, but it gets the job done:
func getMessages(var string: String) -> [String]? {
func getMessage(string: String) -> (message: String, rest: String)? {
guard let
index = string.characters.indexOf("|"),
length = Int(String(string.characters.prefixUpTo(index)))
else { return nil }
let msgRest = String(string.characters.suffixFrom(index.successor()))
return (String(msgRest.utf16.prefix(length)), String(msgRest.utf16.dropFirst(length)))
}
var messages : [String] = []
while let (message, rest) = getMessage(string) {
string = rest
messages.append(message)
}
return messages
}
func stringForMessages(messages: [String]) -> String {
return messages.map{ "\($0.utf16.count)|\($0)" }.joinWithSeparator("")
}
let messages = [
"123",
"💆🏽💆🏽💆🏽",
"🙉😇🎅🏿",
"6🕴⚽️"
]
let string = stringForMessages(messages)
let received = getMessages(string)
messages // ["123", "💆🏽💆🏽💆🏽", "🙉😇🎅🏿", "6🕴⚽️"]
I actually tried making it more efficient, but Swift's String mechanics pushed against it.. I challenge anyone to create a beautiful efficient crash-safe parser for this..

Resources