In my vue/cli 4/vuex / bootstrap-vue project app I install date picker with custom format, like here
https://dbrekalo.github.io/vue-date-pick/examples.html#custom-date-parser
I use moment/moment-timezone in my project, so I do not want to use fecha as in example
I have to convert date value from mysql to datepicker format and I have a problem that my converted date for
datepicker is 1 day bigger...
I have in my component:
<date-pick
v-model="editableAd.expire_date_formatted"
:format="date_picker_format"
:parseDate="parseDate"
:formatDate="formatDate"
:inputAttributes="{size: 32}"
></date-pick>
...
import moment from 'moment-timezone'
console.log('settingsTimeZone::')
console.log(settingsTimeZone) // it shows Europe/Kiev
moment.tz.setDefault(settingsTimeZone)
...
date_picker_format: 'Do MMMM, YYYY',
...
// setting formated date for dapicker
this.editableAd.expire_date_formatted = this.formatDate(this.editableAd.expire_date, this.date_picker_format)
...
formatDate(dateObj) {
console.log('typeof dateObj::')
console.log(typeof dateObj)
console.log(dateObj) // it has ‘2023-01-19’ value
if (typeof dateObj === 'string') {
dateObj = moment(dateObj, this.date_picker_format)
}
console.log('++typeof dateObj::')
console.log(typeof dateObj)
console.log(dateObj)
console.log('RESULT moment(dateObj).format(this.date_picker_format)::')
console.log(moment(dateObj).format(this.date_picker_format)) // BUT it has ‘20th January, 2023’ value
return moment(dateObj).format(this.date_picker_format) // returns invalid ‘20th January, 2023’ value which I see in datepicker
What I see in console for dateObj var : https://imgur.com/a/KZLtXiL
"bootstrap-vue": "^2.1.0",
"font-awesome": "^4.7.0",
"moment": "^2.24.0",
"moment-timezone": "^0.5.27",
"vue": "^2.6.10",
"vue-date-pick": "^1.2.1",
Why error and how it can be fixed?
MODIFIED BLOCK 2:
I removed moment.tz from my project.
In /etc/php/7.2/apache2/php.ini I changed
Timezone ='Europe/Uzhgorod' // That it near my place I live
date.timezone = "Europe/Uzhgorod"
So my phpinfo has this output:
"Olson" Timezone Database Version 0.system
Timezone Database internal
Default timezone Europe/Uzhgorod
I searched how to get a timezone from client browser and found this
get client time zone from browser branch and checking :
var timedifference = new Date().getTimezoneOffset();
console.log('timedifference::')
console.log(timedifference)
var rightNow = new Date();
var jan1 = new Date(rightNow.getFullYear(), 0, 1, 0, 0, 0, 0);
var temp = jan1.toGMTString();
var jan2 = new Date(temp.substring(0, temp.lastIndexOf(" ") - 1));
var std_time_offset = (jan1 - jan2) / (1000 * 60 * 60);
console.log('std_time_offset::')
console.log(std_time_offset)
let jstz = require('jstimezonedetect')
let timezone = jstz.determine()
console.log('timezone::')
console.log(timezone)
console.log('===========================')
I have next output: https://imgur.com/a/84RqqPJ and again running code when I see date is changed +1 day :
console.log('__')
console.log('__')
console.log('typeof dateObj::')
console.log(typeof dateObj)
console.log(dateObj)
if (typeof dateObj === 'string') {
dateObj = moment(dateObj, this.date_picker_format)
}
console.log('++typeof dateObj::')
console.log(typeof dateObj)
console.log(dateObj) // it has ‘2023-01-19’ value
console.log('RESULT moment(dateObj).format(this.date_picker_format)::')
console.log(moment(dateObj).format(this.date_picker_format)) // BUT it has ‘20th January, 2023’ value
return moment(dateObj).format(this.date_picker_format)
and what I see in console: https://imgur.com/a/Y1aSBez
That is strange that .d has 20 day. What is it? Some day zero based option?
The problem you're having is due to some automatic localization formatting. I too don't get why does this happens, since we are providing only dates, they should be treated as such regardless of our timezone. But to solve this issue we have to read it as UTC with moment.utc() and then format it using your desired format.
From vue-date-pick docs example I've worked out a solution using moment.
var app = new Vue({
el: '#app',
components: {
'date-pick': VueDatePick,
},
data: () => ({
format: 'Do MMMM, YYYY',
date: '19th January, 2023',
}),
methods: {
parseDate(value) {
const m = moment.utc(value, this.format);
return new Date(m.year(), m.month(), m.date());
},
formatDate(value) {
return moment.utc(value).format(this.format);
}
}
});
<link href="https://cdn.jsdelivr.net/npm/vue-date-pick#1.2.1/dist/vueDatePick.min.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vue-date-pick#1.2.1/dist/vueDatePick.min.js"></script>
<script src="https://momentjs.com/downloads/moment.min.js"></script>
<script src="https://momentjs.com/downloads/moment-timezone.min.js"></script>
<div id='app'>
<date-pick v-model="date" :format="format" :parse-date="parseDate" :format-date="formatDate"></date-pick>
</div>
Related
I currently have a datetime field in my vue application. I want to split it up, but that would mean having to split it up in my database as well, which I am not interested in. I still want to keep the datetime column in my database table.
So my idea was to make it like 3 seperate fields: datetime, date and time. When a user has entered a date and time, these can be merged into the datetime field.
In Python you would do something like: datetime.datetime.combine( date, time )
Is there are similar method in Vue, or is there a better way of getting around this?
<b-form-row>
<b-col lg="6">
<b-form-group :label="$t('check in time')">
<time-picker v-model="guest.checkInDateTime" />
</b-form-group>
</b-col>
</b-form-row>
<b-form-row>
<b-col lg="6">
<b-form-group :label="$t('check in date')">
<date-picker v-model="guest.checkInDateTime" />
</b-form-group>
</b-col>
</b-form-row>
<b-form-row>
<b-col lg="6">
<b-form-group :label="$t('check in time and date')">
<date-time-picker v-model="guest.checkInDateTime"
:format="format"
:show-second="false"
type="datetime"/>
</b-form-group>
</b-col>
</b-form-row>
Working with dates in Javascript can be nuanced. In Javascript, assuming you have both a date value and a time value, you can easily combine these into a date string used by an html date picker like this:
const date = '2022-08-10' // string returned from date input
const time = '15:00:00' // string returned form time input
const checkInDateTime = date + 'T' + time // ISO String
If you're starting with a Date and you want to break it into a date value and a time value, it's almost easier using string manipulations than working with the Date obj, unless you're using a helper library like dayjs.
Examples:
// Assuming we have a date in ISO String format YYYY-MM-DDTHH:mm:ss
const dateFromString = dateValueFromDB.split('T')[0]
const timeFromString = dateValueFromDB.split('T')[1]
// using Date obj
const d = new Date(dateValueFromDB);
const dateFromObj = `${d.getFullYear()}-${('' + (d.getMonth() + 1)).padStart(2, '0')}-${('' + date.getDate()).padStart(2, '0')}`
const timeFromObj = `${d.getHours()}:${('' + d.getMinutes()).padStart(2,'0')}:${('' + d.getSeconds()).padStart(2,'0')}`
// using dayjs library
const dateFromDayjs = dayjs(dateValueFromDB).format('YYYY-MM-DD')
const timeFromDayjs = dayjs(dateValueFromDB).format('HH:mm:ss')
Now to answer your original question. Once we know how we're getting the correct values, in Vue.js, we can easily get and set these date values using a computed property and a custom setter.
<script>
export default {
data() {
return {
guest: {
checkInDateTime: '2022-09-10 15:00:00' // timestamp returned from database
}
}
},
computed: {
time: {
get() {
return dayjs( this.guest.checkInDateTime ).format('HH:mm:ss')
},
set(val) {
this.guest.checkInDateTime = this.date + 'T' + val
}
},
date: {
get() {
return dayjs(this.guest.checkInDateTime).format('YYYY-MM-DD')
},
set(val) {
this.guest.checkInDateTime = val + 'T' + this.time
}
}
}
}
</script>
Here's the html:
<template>
<div class="datetime-pickers">
<p>date: <input type="date" v-model="date" /></p>
<p>time: <input type="time" v-model="time" /></p>
<p>checkInDateTime: <input type="datetime-local" v-model="guest.checkInDateTime" /></p>
</div>
</template>
When any of the three values are set, the other two are updated accordingly. Here's a CodePen showing this in action:
https://codepen.io/ryanhightower/pen/ExLPobY?editors=1010
I want to change "August 2022" to "2022 August" but i can't find anything similar with this attribute in v-date-picker.
How to change format of this header
Vuetify Datepicker
You have a propery header-date-format that you can use to call your own method of formatting the headers
<v-date-picker
v-model="picker"
:header-date-format="customFormatHeader"
></v-date-picker>
customFormatHeader(isoDate) {
const currentDate = new Date(isoDate)
const month = currentDate.toLocaleString('default', {month: 'long' })
const year = currentDate.toLocaleString('default', { year: 'numeric' })
return year + month
}
I am trying something very simple in Vue and can't get it to work.. I want my API url to update with 2 new values (valueFrom and valueTwo). I am using fetch for this.
When I console log the values, they work (2021-06-17 etc). But as soon as I put them in the url, it just comes up empty.
Here are my input fields:
<label for="dateFrom" class="mr-sm-2">From</label>
<b-form-datepicker id="dateFrom" v-model="valueFrom" class="mb-2 mr-sm-4 mb-sm-0 w-25" :min="min" :max="max"></b-form-datepicker>
<label for="dateTo" class="mr-sm-2">To</label>
<b-form-datepicker id="dateTo" v-model="valueTo" class="mb-2 mr-sm-4 mb-sm-0 w-25" :min="min" :max="max"></b-form-datepicker>
Here is the button that calls the fetch:
<b-button variant="primary" #click="$fetch()">Search</b-button>
Here is my Vue code:
data() {
const now = new Date();
const today = new Date(now.getFullYear(), now.getMonth(), now.getDate());
const minDate = new Date(today);
const maxDate = new Date(today);
maxDate.setMonth(maxDate.getMonth() + 6);
return {
items: {},
valueFrom: '',
valueTo: '',
min: minDate,
max: maxDate
}
},
async fetch() {
const api = 'https://apiurl.com/ajax/locationSearchJSON/?location=Edinburgh&arrival=${this.valueFrom}&arrivalTime=12%3A00&departure={$this.valueTo}&departureTime=12%3A00
this.items = await fetch(api).then(res => res.json())
}
I also tried concating them in the javascript way (' + this.valueFrom + ') but that just rendered an empty string as well...
You can try using the backticks/backquotes (``) in place of the apostrophes. So your url will end up as below:
`https://apiurl.com/ajax/locationSearchJSON/?location=Edinburgh&arrival=${this.valueFrom}&arrivalTime=12%3A00&departure=${this.valueTo}&departureTime=12%3A00`
Also check the second variable this.valueTo has been added to the url correctly. In your case above this is how you've added it:
{$this.valueTo}
It should be:
${this.valueTo}
I receive from a WebAPI a JSON object that has this property:
"BirthDate": "2018-02-14T15:24:17.8177428-03:00",
the HTML:
<input type="date" v-model="BirthDate" />
I bind that object using VueJS, but
VueJS give this message in the console:
The specified value "2018-02-14T15:24:17.8177428-03:00" does not conform to the required format, "yyyy-MM-dd".
On this case the only relevant part is 2018-02-14, I can discard the other information.
I tried to create a Two Way filter to convert that Date Time to the required format but did not have success. See VueJS two way filter
How can I convert and bind that Date/Time format to the required Date Format of the HTML date input ?
Considering myDate is your property, you can use:
<input type="date" :value="myDate && myDate.toISOString().split('T')[0]"
#input="myDate = $event.target.valueAsDate">
Since v-model is only syntactic sugar to :value and #input, you can use them instead. In this case, we used and changed them a little (to format the String that is the output of the date input to a Date object and vice-versa).
Check demo and caveats below.
new Vue({
el: '#app',
data: {
message: 'Hello Vue.js!',
myDate: new Date('2011-04-11T10:20:30Z')
},
methods: {
setMyDateToToday() {
this.myDate = new Date();
},
addADayToMyDate() {
if (this.myDate) // as myDate can be null
// you have to set the this.myDate again, so vue can detect it changed
// this is not a caveat of this specific solution, but of any binding of dates
this.myDate = new Date(this.myDate.setDate(this.myDate.getDate() + 1));
},
}
});
// Notes:
// We use `myDate && myDate.toISOString().split('T')[0]` instead
// of just `myDate.toISOString().split('T')[0]` because `myDate` can be null.
// the date to string conversion myDate.toISOString().split('T')[0] may
// have timezone caveats. See: https://stackoverflow.com/a/29774197/1850609
<script src="https://unpkg.com/vue"></script>
<div id="app">
<p>{{ message }}</p>
<input type="date" :value="myDate && myDate.toISOString().split('T')[0]"
#input="myDate = $event.target.valueAsDate">
<p>
<code>
myDate: {{ myDate }}</code>
</p>
<button #click="setMyDateToToday">Set date one to today</button>
<button #click="addADayToMyDate">Add a day to my date</button>
</div>
i think this not related to vueJs , the input type="date" expected a date in YYYY-MM-DD format, or empty
see here : https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/date,
it would be better if you split date object as date and time field
Correction to #acdcjunior in that this shouldn't be off by one day
new Vue({
el: '#app',
data: {
message: 'Hello Vue.js!',
myDate: new Date('2011-04-11T10:20:30Z')
},
methods: {
setMyDateToToday() {
this.myDate = new Date();
},
addADayToMyDate() {
if (this.myDate) // as myDate can be null
// you have to set the this.myDate again, so vue can detect it changed
// this is not a caveat of this specific solution, but of any binding of dates
this.myDate = new Date(this.myDate.setDate(this.myDate.getDate() + 1));
},
getDateClean(currDate) {
// need to convert to UTC to get working input filter
console.log(currDate);
let month = currDate.getUTCMonth() + 1;
if (month < 10) month = "0" + month;
let day = currDate.getUTCDate();
if (day < 10) day = "0" + day;
const dateStr =
currDate.getUTCFullYear() + "-" + month + "-" + day + "T00:00:00";
console.log(dateStr);
const d = new Date(dateStr);
console.log(d);
return d;
}
}
});
// Notes:
// We use `myDate && myDate.toISOString().split('T')[0]` instead
// of just `myDate.toISOString().split('T')[0]` because `myDate` can be null.
// the date to string conversion myDate.toISOString().split('T')[0] may
// have timezone caveats. See: https://stackoverflow.com/a/29774197/1850609
<script src="https://unpkg.com/vue"></script>
<div id="app">
<p>{{ message }}</p>
<input type="date" :value="myDate && myDate.toISOString().split('T')[0]"
#input="myDate = getDateClean($event.target.valueAsDate)">
<p>
<code>
myDate: {{ myDate }}</code>
</p>
<button #click="setMyDateToToday">Set date one to today</button>
<button #click="addADayToMyDate">Add a day to my date</button>
</div>
I want to know how I can get the information that I have on a sql table into a Kendo scheduler. What I currently have in the server is the Start, End, StartTimeZone, EndTimeZone, Description, Title... etc. All the stuff you need for Kendo Scheduler, but I have many events that I need to make and put into a calendar format and the scheduler seems like the best way to do it. Right now my calendar view looks like this
#(Html.Kendo().Scheduler<**censored**.Models.LeaveRequest>()
.Name("scheduler")
.Date(new DateTime(2013, 6, 13))
.StartTime(new DateTime(2013, 6, 13, 7, 00, 00))
.Height(600)
.Views(views =>
{
views.DayView();
views.WeekView();
views.MonthView(MonthView => MonthView.Selected(true));
})
.Timezone("Etc/UTC")
.DataSource(d => d
.Model(m =>
{
m.Id(f => f.LeaveRequestId);
m.Field(f => f.Title).DefaultValue("No title");
m.Field(f => f.EmployeeId).DefaultValue(1);
m.Field(f => f.Title).DefaultValue("No title");
m.RecurrenceId(f => f.LeaveRequestId);
})
.ServerOperation(true)
.Read(read => read.Action("Read", "Home").Data("getAdditionalData"))
.Create("Create", "Home")
.Destroy("Destroy", "Home")
.Update("Update", "Home")
)
)
<script>
function getAdditionalData() {
var scheduler = $("#scheduler").data("kendoScheduler");
var timezone = scheduler.options.timezone;
var startDate = kendo.timezone.convert(scheduler.view().startDate(), timezone, "Etc/UTC");
var endDate = kendo.timezone.convert(scheduler.view().endDate(), timezone, "Etc/UTC");
//optionally add startTime / endTime of the view
var startTime = kendo.date.getMilliseconds(scheduler.view().startTime());
var endTime = kendo.date.getMilliseconds(scheduler.view().endTime());
endTime = endTime == 0 ? kendo.date.MS_PER_DAY : endTime;
var result = {
Start: new Date(startDate.getTime() - (startDate.getTimezoneOffset() * kendo.date.MS_PER_MINUTE) + startTime),
End: new Date(endDate.getTime() - (endDate.getTimezoneOffset() * kendo.date.MS_PER_MINUTE) + endTime)
}
return result;
}
</script>
<style>
.invalid-slot {
background: red !important;
cursor: no-drop;
}
</style>
</div>
But I don't know what I need to do in the controllers and models, if anything.
I just completed the implementation of KendoUI Scheduler by integrating it with SQL data base. However, I made use of JavaScript API to do so in my MVC project.
To load the data i.e. "read" and perform insert, update and delete just return the model in JSON format from controller. The Scheduler will bind the data for you, if it gets the "know" format.
return Json(**censored**.Models.LeaveRequest, JsonRequestBehavior.AllowGet);
Couple of important points:
1. KendoUI Scheduler depends a lot on unique id, so in case you have anything other than "id" - then "do" configure it in your scheduler.
In JS API it was done using following syntax, where EventID was the unique ID my SQL table.
schema: {
model: {
"id": "EventID",
"fields": {
"EventID": {
"type": "number"
},
....
Always return JSON data from your Insert, Update and Delete method from Controller. For instance:
public JsonResult UpdateCalendarEvent(string models)
{
...
return Json(censored.Models.LeaveRequest, JsonRequestBehavior.AllowGet);
}
In case of Insert, before returning the JSON object, do update the ID or EventID with latest row id, so Scheduler will sync up all data on client side and can perform update and delete operation appropriately.
Hope that helps!